From patchwork Sun Oct 17 00:04:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raoni Fassina Firmino X-Patchwork-Id: 46308 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8E2CD3857C4B for ; Sun, 17 Oct 2021 00:05:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8E2CD3857C4B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1634429121; bh=NepKS1Faqt7MqF40rnAe2RAfAEKSdDCL1WpcvP9Ke7g=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=DAIhg4pmhAOtEolwxb7D6X/Gu7xvkUcQXyfWrhbdToRXpPvmsw9oFsUuI0JjFFaWy 7Xa2BRt7nOV5SHbgccfAZBgbs73rPsaKnRCf3Id/1sAOXyPvq6MpP8uU8WmYRozqDK pJ7Prz1vRdZX7tWADIZGblddoMn98PjNvWEuJPIE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 0FBEB3858D35 for ; Sun, 17 Oct 2021 00:04:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0FBEB3858D35 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 19GLCI8o030316; Sat, 16 Oct 2021 20:04:42 -0400 Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3br6edj78h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 16 Oct 2021 20:04:41 -0400 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 19H003f6021581; Sat, 16 Oct 2021 20:04:40 -0400 Received: from ppma03dal.us.ibm.com (b.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.11]) by mx0a-001b2d01.pphosted.com with ESMTP id 3br6edj785-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 16 Oct 2021 20:04:40 -0400 Received: from pps.filterd (ppma03dal.us.ibm.com [127.0.0.1]) by ppma03dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 19H04YLh026335; Sun, 17 Oct 2021 00:04:39 GMT Received: from b01cxnp22035.gho.pok.ibm.com (b01cxnp22035.gho.pok.ibm.com [9.57.198.25]) by ppma03dal.us.ibm.com with ESMTP id 3bqpc9b73t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 17 Oct 2021 00:04:39 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp22035.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 19H04KWT40304900 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 17 Oct 2021 00:04:20 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BF24DAC05B; Sun, 17 Oct 2021 00:04:20 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 849DFAC059; Sun, 17 Oct 2021 00:04:18 +0000 (GMT) Received: from work-tp (unknown [9.65.237.149]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTPS; Sun, 17 Oct 2021 00:04:18 +0000 (GMT) Date: Sat, 16 Oct 2021 21:04:15 -0300 To: gcc-patches@gcc.gnu.org Subject: [PATCH v6] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193] Message-ID: <20211017000415.vqt5yyrq7j7kg5c4@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, law@redhat.com, will_schmidt@vnet.ibm.com Content-Disposition: inline X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: aDF3BwyFFVz0C1o1jU-uH9uXvYCFLtax X-Proofpoint-GUID: qZRfEshAO_zF0cB3UuyMqeRRFw81Fqam X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-10-16_07,2021-10-14_02,2020-04-07_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 lowpriorityscore=0 impostorscore=0 malwarescore=0 phishscore=0 adultscore=0 spamscore=0 clxscore=1011 priorityscore=1501 mlxscore=0 bulkscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109230001 definitions=main-2110160164 X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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-Patchwork-Original-From: Raoni Fassina Firmino via Gcc-patches From: Raoni Fassina Firmino Reply-To: Raoni Fassina Firmino Cc: jakub@redhat.com, rguenther@suse.de, segher@kernel.crashing.org, law@redhat.com, joseph@codesourcery.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Changes since v5[5]: - Reworked all builtins to accept the FE_* macros as parameters and so be agnostic to libc implementations. Largely based of fpclassify. To that end, there is some new files changed: + Change the argument list for the builtins declarations in builtins.def + Added new types in builtin-types.def to use in the buitins declarations. + Added extra documentation for the builtins on doc/extend.texi, similar to fpclassify. - Updated doc/md.texi documentation with the new optab behaviors. - Updated comments to the expanders and expand handlers to try to explain whats is going on. - Changed the description for the return operand in the RTL template of the fegetround expander. Using "(set )", the same way as rs6000_mffsl expander. - Updated testcases with helper macros with the new argument list. Tested on top of master (f7571527a44808cd7062c77bb9570c13f4f6a126) on the following plataforms with no regression: - powerpc64le-linux-gnu (Power 9) - powerpc64le-linux-gnu (Power 8) - powerpc64-linux-gnu (Power 9, with 32 and 64 bits tests) Documentation changes tested on x86_64-redhat-linux. This approach left me with some hanging problems that I am not quite sure how to go about it. First is the different arguments from the C99 functions. I think the solution is a macro to correct this, like so: #define feclearexcept(excepts) \ __builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT, \ FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) That is automatically always included or included when fenv.h is included. Does the preprocessor have this ability? If so, where should I put it? But this solution seems to have a problem that it will bypass -fno-builtin, unless there can be a conditional check for it on the preprocessor. Second is the fallback of the expanders. When the expanders fail it will leave the function call, which is great, but since the argument list is different, well, it not is pretty. There is no execution problem, since the builtins only having extra arguments, but it generate extra unnecessary code. Here is an example, a snipped of the generated assembly from the builtin-feclearexcept-feraiseexcept-1.c testcase: # builtin-feclearexcept-feraiseexcept-1.c:36: __builtin_feclearexcept(FE_INVALID); // CALL lis %r8,0x800 lis %r7,0x1000 lis %r6,0x2000 lis %r5,0x200 lis %r4,0x400 lis %r3,0x2000 bl feclearexcept I assume I can modify the RTL to remove the unneeded arguments. If so, there is pointer where this is done or how I can do it? I'm also adding some extra documentation for the builtins section, the doc/extend.texi, close to where the fpclassify documentation is[6], but I don't know if I'm doing it right, especially changing such a front facing documentation. I'm repeating the "changelog" from past versions here for convenience: Changes since v4[4]: - Fixed more spelling and code style. - Add more clarification on comments for feraiseexcept and feclearexcept expands; Changes since v3[3]: - Fixed fegetround bug on powerpc64 (big endian) that Segher spotted; Changes since v2[2]: - 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. Changes since v1[1]: - Fixed english spelling; - Fixed code-style; - Changed match operand predicate in feclearexcept and feraiseexcept; - Changed testcase options; - Minor changes in test code to be C90 compatible; - Other minor changes sugested by Segher; - Changed subject line tag (not sure if I tagged correctly or should include optabs: also) [1] https://gcc.gnu.org/pipermail/gcc-patches/2020-August/552024.html [2] https://gcc.gnu.org/pipermail/gcc-patches/2020-September/553297.html [3] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557109.html [4] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557349.html [5] https://gcc.gnu.org/pipermail/gcc-patches/2020-November/557984.html [6] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins ---- 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. There is signature changes to all three builtins relative to the correspondent libc function, the extra arguments add a way to make the builtins work agnostic of the libc implementations. 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: * builtin-types.def (BT_FN_INT_INT_INT_INT_INT): New type. (BT_FN_INT_INT_INT_INT_INT_INT_INT): New type. * 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 * builtins.def (BUILT_IN_FECLEAREXCEPT): Change type. (BUILT_IN_FEGETROUND): Change type. (BUILT_IN_FERAISEEXCEPT): Change type. * config/rs6000/rs6000.md (fegetroundsi): New pattern. (feclearexceptsi): New Pattern. (feraiseexceptsi): New Pattern. * doc/extend.texi: Add a new introductory paragraph about the new builtins. (__builtin_feclearexcept): Document new builtin. (__builtin_feclearexcept): Document new builtin. (__builtin_feraiseexcept): Document new builtin. * doc/md.texi: (fegetround@var{m}): Document new optab. (feclearexcept@var{m}): Document new optab. (feraiseexcept@var{m}): Document new optab. * 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/builtin-types.def | 4 + gcc/builtins.c | 100 +++++++++ gcc/builtins.def | 6 +- gcc/config/rs6000/rs6000.md | 163 ++++++++++++++ gcc/doc/extend.texi | 51 +++++ gcc/doc/md.texi | 21 ++ gcc/optabs.def | 4 + .../builtin-feclearexcept-feraiseexcept-1.c | 82 +++++++ .../builtin-feclearexcept-feraiseexcept-2.c | 209 ++++++++++++++++++ .../gcc.target/powerpc/builtin-fegetround.c | 39 ++++ 10 files changed, 676 insertions(+), 3 deletions(-) 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/builtin-types.def b/gcc/builtin-types.def index d160826e1d4f..0520772801e6 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -680,6 +680,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR, BT_PTR_ULONGLONG) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_UINT_PTR_INT_PTR, BT_VOID, BT_INT, BT_PTR, BT_INT, BT_PTR) +DEF_FUNCTION_TYPE_4 (BT_FN_INT_INT_INT_INT_INT, + BT_INT, BT_INT, BT_INT, BT_INT, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING, @@ -737,6 +739,8 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, BT_INT) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_INT_INT_INT_INT_INT_INT_INT, + BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, diff --git a/gcc/builtins.c b/gcc/builtins.c index f1c3fea3583d..da51ed25711a 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -119,6 +119,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); @@ -2527,6 +2530,83 @@ expand_builtin_sincos (tree exp) return const0_rtx; } +/* Expand call EXP to __builtin_fegetround(int, int, int, int), returning the + result and setting it in TARGET. Otherwise return NULL_RTX on failure. + This builtin implements fegetround (from C99 fenv.h) and will generate code + to return the current floating point rounding mode. The possible return + values must be supplied as int arguments to the call in the following order: + FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO and FE_UPWARD. This enables the + builtin to work agnostic of the c library's values for the rounding modes. */ +static rtx +expand_builtin_fegetround (tree exp, rtx target, machine_mode target_mode) +{ + if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, + INTEGER_TYPE, INTEGER_TYPE, 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 op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); + rtx op2 = expand_normal (CALL_EXPR_ARG (exp, 2)); + rtx op3 = expand_normal (CALL_EXPR_ARG (exp, 3)); + + rtx pat = GEN_FCN (icode) (target, op0, op1, op2, op3); + if (!pat) + return NULL_RTX; + emit_insn (pat); + + return target; +} + +/* Expand call EXP to __builtin_feclearexcept(int, int, int, int, int, int) or + or __builtin_feraiseexcept(int, int, int, int, int, int), returning the + result and setting it in TARGET. Otherwise return NULL_RTX on failure. + This builtins implements feclearexcept and feraiseexcept (from C99 fenv.h) + and will generate code to clear or raise floating point exceptions supplied + as the first argument. The possible exceptions values must be supplied as + the last five int arguments to the call in the following order: FE_DIVBYZERO, + FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW. This enables the + builtin work agnostic of the c library's values for the exceptions. */ +static rtx +expand_builtin_feclear_feraise_except (tree exp, rtx target, + machine_mode target_mode, optab op_optab) +{ + if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, + INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return NULL_RTX; + + 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 op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); + rtx op2 = expand_normal (CALL_EXPR_ARG (exp, 2)); + rtx op3 = expand_normal (CALL_EXPR_ARG (exp, 3)); + rtx op4 = expand_normal (CALL_EXPR_ARG (exp, 4)); + rtx op5 = expand_normal (CALL_EXPR_ARG (exp, 5)); + + rtx pat = GEN_FCN (icode) (target, op0, op1, op2, op3, op4, op5); + 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. */ @@ -7033,6 +7113,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/builtins.def b/gcc/builtins.def index 45a09b4d42de..65157f3e21c0 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -364,12 +364,12 @@ DEF_C2X_BUILTIN (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128 DEF_C99_BUILTIN (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) -DEF_C99_BUILTIN (BUILT_IN_FECLEAREXCEPT, "feclearexcept", BT_FN_INT_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_C99_BUILTIN (BUILT_IN_FECLEAREXCEPT, "feclearexcept", BT_FN_INT_INT_INT_INT_INT_INT_INT, ATTR_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_FEGETENV, "fegetenv", BT_FN_INT_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_FEGETEXCEPTFLAG, "fegetexceptflag", BT_FN_INT_FEXCEPT_T_PTR_INT, ATTR_NOTHROW_LEAF_LIST) -DEF_C99_BUILTIN (BUILT_IN_FEGETROUND, "fegetround", BT_FN_INT, ATTR_PURE_NOTHROW_LEAF_LIST) +DEF_C99_BUILTIN (BUILT_IN_FEGETROUND, "fegetround", BT_FN_INT_INT_INT_INT_INT, ATTR_PURE_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_FEHOLDEXCEPT, "feholdexcept", BT_FN_INT_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST) -DEF_C99_BUILTIN (BUILT_IN_FERAISEEXCEPT, "feraiseexcept", BT_FN_INT_INT, ATTR_NULL) +DEF_C99_BUILTIN (BUILT_IN_FERAISEEXCEPT, "feraiseexcept", BT_FN_INT_INT_INT_INT_INT_INT_INT, ATTR_NULL) DEF_C99_BUILTIN (BUILT_IN_FESETENV, "fesetenv", BT_FN_INT_CONST_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_FESETEXCEPTFLAG, "fesetexceptflag", BT_FN_INT_CONST_FEXCEPT_T_PTR_INT, ATTR_NULL) DEF_C99_BUILTIN (BUILT_IN_FESETROUND, "fesetround", BT_FN_INT_INT, ATTR_NOTHROW_LEAF_LIST) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 6bec2bddbdee..1161aa831258 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -6860,6 +6860,169 @@ [(set_attr "type" "fpload") (set_attr "length" "8") (set_attr "isa" "*,p8v,p8v")]) + +;; int __builtin_fegetround(int, int, int, int) +;; +;; This built-in implements the C99 fegetround functionality. +;; The four int arguments should be the target library's notion of the +;; possible FP rouding modes. They must be constant values and they +;; must appear in this order: FE_DOWNWARD, FE_TONEAREST, +;; FE_TOWARDZERO, FE_UPWARD. In other words: +;; +;; __builtin_fegetround(FE_DOWNWARD, FE_TONEAREST, +;; FE_TOWARDZERO, FE_UPWARD) +;; +;; This values are used to match the processor values for the rounding +;; mode with the target library's. For now, to avoid the cost of +;; converting between them, the behavior is to not expand if they are +;; different and fallback to a call to libc. +(define_expand "fegetroundsi" + [(use (match_operand:SI 4 "const_int_operand" "n")) + (use (match_operand:SI 3 "const_int_operand" "n")) + (use (match_operand:SI 2 "const_int_operand" "n")) + (use (match_operand:SI 1 "const_int_operand" "n")) + (set (match_operand:SI 0 "gpc_reg_operand") + (unspec_volatile:SI [(const_int 0)] UNSPECV_MFFSL))] + "TARGET_HARD_FLOAT" +{ + unsigned int fe_downward = INTVAL (operands[1]); + unsigned int fe_tonearest = INTVAL (operands[2]); + unsigned int fe_towardzero = INTVAL (operands[3]); + unsigned int fe_upward = INTVAL (operands[4]); + + if (fe_downward != 3 + || fe_tonearest != 0 + || fe_towardzero != 1 + || fe_upward != 2) + FAIL; + + 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 __builtin_feclearexcept(int, int, int, int, int, int) +;; +;; This built-in implements the C99 feclearexcept functionality. The +;; first argument is the original feclearexcept() EXCEPTS argument. +;; The other five int arguments should be the target library's notion +;; of the possible FP exceptions. They must be constant values and +;; they must appear in this order: FE_DIVBYZERO, FE_INEXACT, +;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW. In other words: +;; +;; __builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT, +;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) +;; +;; This values are used to match the processor values for the +;; exception with the target library's. +;; This expansion for the builtin only works when EXCEPTS (the last +;; argument) 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 6 "const_int_operand" "n")) + (use (match_operand:SI 5 "const_int_operand" "n")) + (use (match_operand:SI 4 "const_int_operand" "n")) + (use (match_operand:SI 3 "const_int_operand" "n")) + (use (match_operand:SI 2 "const_int_operand" "n")) + (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 excepts = INTVAL (operands[1]); + unsigned int fe_divbyzero = INTVAL (operands[2]); + unsigned int fe_inexact = INTVAL (operands[3]); + unsigned int fe_overflow = INTVAL (operands[5]); + unsigned int fe_underflow = INTVAL (operands[6]); + unsigned int valid_excepts = fe_divbyzero + | fe_inexact + | fe_overflow + | fe_underflow; + + if (excepts != (excepts & valid_excepts)) + FAIL; + + if (excepts & fe_divbyzero) + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 5))); + if (excepts & fe_inexact) + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 6))); + if (excepts & fe_underflow) + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 4))); + if (excepts & fe_overflow) + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 3))); + + emit_move_insn (operands[0], const0_rtx); + DONE; +}) + +;; int __builtin_feraiseexcept(int, int, int, int, int, int) +;; +;; This built-in implements the C99 feraiseexcept functionality. The +;; first argument is the original feraiseexcept() EXCEPTS argument. +;; The other five int arguments should be the target library's notion +;; of the possible FP exceptions. They must be constant values and +;; they must appear in this order: FE_DIVBYZERO, FE_INEXACT, +;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW. In other words: +;; +;; __builtin_feraiseexcept(excepts, FE_DIVBYZERO, FE_INEXACT, +;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) +;; +;; This values are used to match the processor values for the +;; exception with the target library's. +;; This expansion for the builtin only works when EXCEPTS (the last +;; argument) 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 6 "const_int_operand" "n")) + (use (match_operand:SI 5 "const_int_operand" "n")) + (use (match_operand:SI 4 "const_int_operand" "n")) + (use (match_operand:SI 3 "const_int_operand" "n")) + (use (match_operand:SI 2 "const_int_operand" "n")) + (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 excepts = INTVAL (operands[1]); + unsigned int fe_divbyzero = INTVAL (operands[2]); + unsigned int fe_inexact = INTVAL (operands[3]); + unsigned int fe_overflow = INTVAL (operands[5]); + unsigned int fe_underflow = INTVAL (operands[6]); + unsigned int valid_excepts = fe_divbyzero + | fe_inexact + | fe_overflow + | fe_underflow; + + if (excepts != (excepts & valid_excepts)) + FAIL; + + if (excepts & fe_divbyzero) + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 5))); + if (excepts & fe_inexact) + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 6))); + if (excepts & fe_underflow) + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 4))); + if (excepts & 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/extend.texi b/gcc/doc/extend.texi index 10d466fae9a4..fdd76579ce33 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12858,6 +12858,9 @@ is called and the @var{flag} argument passed to it. @findex __builtin_alloca_with_align_and_max @findex __builtin_call_with_static_chain @findex __builtin_extend_pointer +@findex __builtin_feclearexcept +@findex __builtin_fegetround +@findex __builtin_feraiseexcept @findex __builtin_fpclassify @findex __builtin_has_attribute @findex __builtin_isfinite @@ -13424,6 +13427,16 @@ In the same fashion, GCC provides @code{fpclassify}, @code{isfinite}, @code{__builtin_} prefixed. The @code{isinf} and @code{isnan} built-in functions appear both with and without the @code{__builtin_} prefix. +GCC provides built-in versions of the ISO C99 floating-point rounding and +exceptions handling functions @code{fegetround}, @code{feclearexcept} and +@code{feraiseexcept}. This built-in versions take extra arguments to describe +the c library's notion of the possible rounding modes and exceptions values and +are used internally to enable an transparent approach independent of the c +library used. We intend for a library implementer to be able to simply +@code{#define} each function to its built-in equivalent with the extra +arguments. This built-in functions appear both with and without the +@code{__builtin_} prefix. + @deftypefn {Built-in Function} void *__builtin_alloca (size_t size) The @code{__builtin_alloca} function must be called at block scope. The function allocates an object @var{size} bytes large on the stack @@ -14197,6 +14210,44 @@ Similar to @code{__builtin_huge_val}, except the return type is @code{_Float@var{n}x}. @end deftypefn +@deftypefn {Built-in Function} int __builtin_fegetround (int, int, int, int) +This built-in implements the C99 fegetround functionality. The four int +arguments should be the target library's notion of the possible FP rouding +modes. They must be constant values and they must appear in this order: +@code{FE_DOWNWARD}, @code{FE_TONEAREST}, @code{FE_TOWARDZERO}, +@code{FE_UPWARD}. In other words: + +@smallexample +__builtin_fegetround(FE_DOWNWARD, FE_TONEAREST, + FE_TOWARDZERO, FE_UPWARD) +@end smallexample + +This values are used to match the processor values for the rounding +mode with the target library's. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_feclearexcept (int, int, int, int, int, int) +This built-in implements the C99 feclearexcept functionality. The first +argument is the original feclearexcept() EXCEPTS argument. The other five int +arguments should be the target library's notion of the possible FP exceptions. +They must be constant values and they must appear in this order: +@code{FE_DIVBYZERO}, @code{FE_INEXACT}, @code{FE_INVALID}, @code{FE_OVERFLOW}, +@code{FE_UNDERFLOW}. In other words: + +@smallexample +__builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT, + FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) +@end smallexample + +This values are used to match the processor values for the exception with the +target library's. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_feraiseexcept (int, int, int, int, int, int) +Analogous to @code{__builtin_feclearexcept}, except to raise excepts instead of +clearing and all arguments have the same semantics. +@end deftypefn + @deftypefn {Built-in Function} int __builtin_fpclassify (int, int, int, int, int, ...) This built-in implements the C99 fpclassify functionality. The first five int arguments should be the target library's notion of the diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 41f1850bf6e9..9b39a09f1892 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -6053,6 +6053,27 @@ 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. +Libc values for FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO and FE_UPWARD +are passed to operands 1, 2, 3 and 4 respectively. All operands have +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. Libc values for FE_DIVBYZERO, +FE_INEXACT, FE_INVALID, FE_OVERFLOW and FE_UNDERFLOW are passed to +operands 2, 3, 4, 5 and 6 respectively. 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 f02c7b729a51..49f8d33bcf0d 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -327,6 +327,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 000000000000..f8c3b072fe3f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c @@ -0,0 +1,82 @@ +/* { 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 + +#define __builtin_feraiseexcept(x) \ + __builtin_feraiseexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) + +#define __builtin_feclearexcept(x) \ + __builtin_feclearexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) + +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 000000000000..397396623532 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c @@ -0,0 +1,209 @@ +/* { 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 + +#define __builtin_feraiseexcept(x) \ + __builtin_feraiseexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) + +#define __builtin_feclearexcept(x) \ + __builtin_feclearexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW) + +#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 000000000000..94238af6c287 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c @@ -0,0 +1,39 @@ +/* { 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 + +#define __builtin_fegetround(x) \ + __builtin_fegetround(FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD) + +#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; +}