From patchwork Wed Nov 24 23:48:47 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: 48116 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 AB4BD385800C for ; Wed, 24 Nov 2021 23:49:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AB4BD385800C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1637797783; bh=CM3adTTTnwIktvUR2L0THLygR5lJ5nKvVVPHyx1mh4M=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=tqLNyPbqRaiRqvvOFczTj0YCFPdBy0/2Qd2TwRsRUB0e/qSwPvi5L61eyAzfmlGgR Dtn+kcMc5DiPDz5ysbmhlxRu7zxIxWqPTlAuisEgBwwRqdGmdIwqNOf066BYnkWEU0 IjnCDV4nIOgdAw5iJdlBdDO0UOSavfjya8rHBt9g= 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 7E87C3858403 for ; Wed, 24 Nov 2021 23:49:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7E87C3858403 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 1AOMpl8I002502; Wed, 24 Nov 2021 23:49:05 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3chxjbrr28-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 24 Nov 2021 23:49:05 +0000 Received: from m0098404.ppops.net (m0098404.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 1AONn43j017851; Wed, 24 Nov 2021 23:49:04 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com with ESMTP id 3chxjbrr1v-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 24 Nov 2021 23:49:04 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 1AONWjoG016380; Wed, 24 Nov 2021 23:49:03 GMT Received: from b03cxnp07028.gho.boulder.ibm.com (b03cxnp07028.gho.boulder.ibm.com [9.17.130.15]) by ppma02wdc.us.ibm.com with ESMTP id 3cernbbj14-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 24 Nov 2021 23:49:03 +0000 Received: from b03ledav004.gho.boulder.ibm.com (b03ledav004.gho.boulder.ibm.com [9.17.130.235]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 1AONn2d028574460 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 24 Nov 2021 23:49:02 GMT Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3C19A7806E; Wed, 24 Nov 2021 23:49:02 +0000 (GMT) Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EA9B678068; Wed, 24 Nov 2021 23:48:59 +0000 (GMT) Received: from work-tp (unknown [9.65.226.233]) by b03ledav004.gho.boulder.ibm.com (Postfix) with ESMTPS; Wed, 24 Nov 2021 23:48:59 +0000 (GMT) Date: Wed, 24 Nov 2021 20:48:47 -0300 To: gcc-patches@gcc.gnu.org Subject: [PATCH v7] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193] Message-ID: <20211124234847.tw7xh6pldu5me3mv@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-GUID: fv1XO40sGe-GhaL-Bwhvhk8nwuH-B45a X-Proofpoint-ORIG-GUID: JnzkhJWTDeUk1BWNXjjmPVcn2ISeK3TO X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-11-24_06,2021-11-24_01,2020-04-07_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 priorityscore=1501 mlxscore=0 adultscore=0 impostorscore=0 bulkscore=0 phishscore=0 mlxlogscore=999 clxscore=1015 lowpriorityscore=0 malwarescore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2110150000 definitions=main-2111240115 X-Spam-Status: No, score=-10.6 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 v6[6] and v5[5]: - Based this version on the v5 one. - Reworked all builtins back to the way they are in v5 and added the following changes: + Added a test to target libc, only expanding with glibc as the target libc. + Updated all three expanders header comment to reflect the added behavior (fegetround got a full header as it had none). + Added extra documentation for the builtins on doc/extend.texi, similar to v6 version, but only the introductory paragraph, without a dedicated entry for each, since now they behavior and signature match the C99 ones. - Changed the description for the return operand in the RTL template of the fegetround expander. Using "(set )", the same way as rs6000_mffsl expander (this change was taken from v6). - Updated the commit message mentioning the target libc restriction and updated changelog. Tested on top of master (9bf69a8558638ce0cdd69e83a68776deb9b8e053) 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) Also made a visual test comparing the generated assembly of a test program built against glibc and musl (with -mmusl and with musl-gcc). Documentation changes tested on x86_64-redhat-linux. Well, turns out v6 was kind of a misstep[7]. But turns out the solution was in my face the whole time and Joseph was kind enough to spell it out to me. I should have known, one can check for the target libc at runtime. It is a really simple addition to each expander, only expanding for the libcs the expander know the FE_* and can handle it. As Joseph mentioned on his review, with that the expander don't have to always expand and everything is fine. As I mentioned[8], musl and uclibc both uses the same values as glibc, I could add then enabling the expanders for them, not sure about it. I don't know if I should add something to the documentation, more precisely on section "6.59 Other Built-in Functions Provided by GCC" in doc/extend.text. Like I mentioned in v6 but I don't know if I'm doing it right, especially changing such a front facing documentation, but here it is. I'm repeating the "changelog" from past versions here for convenience: 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. 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 counterpart; - 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 suggested 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/pipermail/gcc-patches/2021-October/581837.html [7] https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581929.html [8] https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558070.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 builtin expanders needs knowledge of the target libc's FE_* values, so they are limited to expand only to suitable libcs. 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. * doc/extend.texi: Add a new introductory paragraph about the new builtins. * 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/builtins.c | 76 +++++++ gcc/config/rs6000/rs6000.md | 111 ++++++++++ gcc/doc/extend.texi | 8 + 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 ++++ 8 files changed, 531 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 384864bfb3a4..40690b133ebd 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,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. */ @@ -7006,6 +7062,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 6bec2bddbdee..1aae3e83d64c 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -6860,6 +6860,117 @@ [(set_attr "type" "fpload") (set_attr "length" "8") (set_attr "isa" "*,p8v,p8v")]) + +;; int fegetround(void) +;; +;; This expansion for the C99 function only expands for compatible +;; target libcs. Because it needs to return one of FE_DOWNWARD, +;; FE_TONEAREST, FE_TOWARDZERO or FE_UPWARD with the values as defined +;; by the target libc, and since they are free to +;; choose the values and the expand needs to know then beforehand, +;; this expand only expands for target libcs that it can handle the +;; values is knows. +;; Because of these restriction, this only expands on the desired +;; case and fallback to a call to libc on any otherwise. +(define_expand "fegetroundsi" + [(set (match_operand:SI 0 "gpc_reg_operand") + (unspec_volatile:SI [(const_int 0)] UNSPECV_MFFSL))] + "TARGET_HARD_FLOAT" +{ + if (!OPTION_GLIBC) + 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 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. +;; The FE_* are defined in the targed libc, and since they are free to +;; choose the values and the expand needs to know then beforehand, +;; this expand only expands for target libcs that it can handle the +;; values is knows. +;; 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" +{ + if (!OPTION_GLIBC) + FAIL; + + 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. +;; The FE_* are defined in the targed libc, and since they are free to +;; choose the values and the expand needs to know then beforehand, +;; this expand only expands for target libcs that it can handle the +;; values is knows. +;; 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" +{ + if (!OPTION_GLIBC) + FAIL; + + 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/extend.texi b/gcc/doc/extend.texi index ef654d7b8788..92d3a6880c74 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -13426,6 +13426,14 @@ 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}. They may not be available for all targets, and because +they need close interaction with libc internal values, they may not be available +for all target libcs, but in all cases they will gracefully fallback to libc +calls. 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 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 589f841ea741..0d4800694b16 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -6053,6 +6053,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 e25f4c9a3466..00620e18b7c2 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -330,6 +330,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..c9d5b5cefc0f --- /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 000000000000..e1bf8091014b --- /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 000000000000..502ddf30ae2f --- /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; +}