From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1005) id 034F6385482F; Mon, 19 Apr 2021 02:10:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 034F6385482F Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Michael Meissner To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/meissner/heads/work048)] Fix Fortran rounding issues. X-Act-Checkin: gcc X-Git-Author: Michael Meissner X-Git-Refname: refs/users/meissner/heads/work048 X-Git-Oldrev: 56ebac331697587ebd5d404eabdf855edb887e94 X-Git-Newrev: 3c8ae8fff685b3fd6a4917fda1bcf3ce0adef3d5 Message-Id: <20210419021046.034F6385482F@sourceware.org> Date: Mon, 19 Apr 2021 02:10:46 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Apr 2021 02:10:46 -0000 https://gcc.gnu.org/g:3c8ae8fff685b3fd6a4917fda1bcf3ce0adef3d5 commit 3c8ae8fff685b3fd6a4917fda1bcf3ce0adef3d5 Author: Michael Meissner Date: Sun Apr 18 22:10:19 2021 -0400 Fix Fortran rounding issues. I was looking at Fortran PR 96983, which fails on the PowerPC when trying to run the test PR96711.F90. The compiler ICEs because the PowerPC does not have a floating point type with a type precision of 128. The reason is that the PowerPC has 3 different 128 bit floating point types (__float128/_Float128, __ibm128, and long double). Currently long double uses the IBM extended double type, but we would like to switch to using IEEE 128-bit long doubles in the future. In order to prevent the compiler from converting explicit __ibm128 types to long double when long double uses the IEEE 128-bit representation, we have set up the precision for __ibm128 to be 128, long double to be 127, and __float128/_Float128 to be 126. Originally, I was trying to see if for Fortran, I could change the precision of long double to be 128 (Fortran doesn't access __ibm128), but it quickly became hard to get the changes to work. I looked at the Fortran code in build_round_expr, and I came to the conclusion that there is no reason to promote the floating point type. Just do a normal round of the value and then convert it to the integer type. This patch fixes that. However, while with this patch, the PowerPC compiler will not crash when building the test case, it will not run on the current default installation. This is because the test is explicitly expecting 128-bit floating point to handle 10384593717069655257060992658440192_16 (i.e. 2**113). This is because the IBM extended double used for 128-bit floating point by default cannot handle exponents larger than 2**53, due to the floating point type being a pair of doubles that gives more mantissa range, but not more exponent range. If I build the compiler where the default long double is IEEE 128-bit, then the test runs fine. Now, I've not contributed to the Fortran front end before. If the maintainers like the patch, can somebody point out if I need to do additional things to commit the patch? gcc/fortran/ 2021-04-18 Michael Meissner PR gfortran/96983 * trans-intrinsic.c (build_round_expr): If int type is larger than long long, do the round and convert to the integer type. Do not try to find a floating point type the exact size of the integer type. Diff: --- gcc/fortran/trans-intrinsic.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 5e53d1162fa..cceef8f34ac 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -386,30 +386,20 @@ build_round_expr (tree arg, tree restype) argprec = TYPE_PRECISION (argtype); resprec = TYPE_PRECISION (restype); - /* Depending on the type of the result, choose the int intrinsic - (iround, available only as a builtin, therefore cannot use it for - __float128), long int intrinsic (lround family) or long long - intrinsic (llround). We might also need to convert the result - afterwards. */ + /* Depending on the type of the result, choose the int intrinsic (iround, + available only as a builtin, therefore cannot use it for __float128), long + int intrinsic (lround family) or long long intrinsic (llround). If we + don't have an appropriate function that converts directly to the integer + type (such as kind == 16), just use ROUND, and then convert the result to + an integer. We might also need to convert the result afterwards. */ if (resprec <= INT_TYPE_SIZE && argprec <= LONG_DOUBLE_TYPE_SIZE) fn = builtin_decl_for_precision (BUILT_IN_IROUND, argprec); else if (resprec <= LONG_TYPE_SIZE) fn = builtin_decl_for_precision (BUILT_IN_LROUND, argprec); else if (resprec <= LONG_LONG_TYPE_SIZE) fn = builtin_decl_for_precision (BUILT_IN_LLROUND, argprec); - else if (resprec >= argprec && resprec == 128) - { - /* Search for a real kind suitable as temporary for conversion. */ - int kind = -1; - for (int i = 0; kind < 0 && gfc_real_kinds[i].kind != 0; i++) - if (gfc_real_kinds[i].mode_precision >= resprec) - kind = gfc_real_kinds[i].kind; - if (kind < 0) - gfc_internal_error ("Could not find real kind with at least %d bits", - resprec); - arg = fold_convert (gfc_get_real_type (kind), arg); - fn = gfc_builtin_decl_for_float_kind (BUILT_IN_ROUND, kind); - } + else if (resprec >= argprec) + fn = builtin_decl_for_precision (BUILT_IN_ROUND, argprec); else gcc_unreachable ();