From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11154 invoked by alias); 21 May 2014 14:46:27 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 11139 invoked by uid 89); 21 May 2014 14:46:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.8 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 21 May 2014 14:46:24 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s4LEkLcc027664 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 21 May 2014 10:46:22 -0400 Received: from tucnak.zalov.cz (ovpn-116-17.ams2.redhat.com [10.36.116.17]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s4LEkJKI012222 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 21 May 2014 10:46:20 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.14.8/8.14.7) with ESMTP id s4LEkGQq011093; Wed, 21 May 2014 16:46:16 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.14.8/8.14.8/Submit) id s4LEkEHG011092; Wed, 21 May 2014 16:46:14 +0200 Date: Wed, 21 May 2014 14:46:00 -0000 From: Jakub Jelinek To: Marek Polacek Cc: "Joseph S. Myers" , GCC Patches Subject: Re: [PATCH] Implement -fsanitize=float-cast-overflow (take 2) Message-ID: <20140521144614.GT10386@tucnak.redhat.com> Reply-To: Jakub Jelinek References: <20140513170801.GG2663@redhat.com> <20140514113839.GE10386@tucnak.redhat.com> <20140515190929.GQ10386@tucnak.redhat.com> <20140516073654.GS10386@tucnak.redhat.com> <20140520203343.GF4561@redhat.com> <20140521125100.GB5135@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="jTMWTj4UTAEmbWeb" Content-Disposition: inline In-Reply-To: <20140521125100.GB5135@redhat.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes X-SW-Source: 2014-05/txt/msg01785.txt.bz2 --jTMWTj4UTAEmbWeb Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2662 On Wed, May 21, 2014 at 02:51:00PM +0200, Marek Polacek wrote: > On Tue, May 20, 2014 at 09:50:10PM +0000, Joseph S. Myers wrote: > > On Tue, 20 May 2014, Marek Polacek wrote: > > > > > * is missing tests for long doubles/-mlong-double-128, > > > > Also missing tests for float - as far as I can see, only double is tested. > > Ideally all of float, double, long double, __float128 (where supported), > > __float80 (where supported) would be tested (the functionality supported > > for __fp16 (ARM) is a bit more restricted) - hopefully using some shared > > macros to avoid too much duplication between tests. > > Ok, I've added some tests for float, long double, __float128 and > __float80. A snag was in __float128 type: libubsan supposedly can't > handle __float128 values and prints "0". libubsan also can't handle > __float80 types with -m32 it seems. > Common macros moved to float-cast.h. Clearly libubsan doesn't support _Decimal* either, so I guess for now we should just avoid emitting any __ubsan_* diagnostics for any of the __float{80,128} or _Decimal{32,64,128} types for now, and work with upstream to add support for that (given the problematic design where a type is identified only by kind and bitsize, I guess for _Decimal* we need to use a different (new) kind, not sure what can be done about __float{80,128}, as libubsan treats both bitsize 80 and 128 as long double. Note that libstdc++ doesn't support conversion of _Decimal{32,64,128} nor std::decimal::decimal{32,64,128} to strings, and not sure if libubsan would like to be linked against something that rarely used as libdecnumber. So, I guess at least for now, we should have a way to tell libubsan about those types (both decimal and __float{80,128}, but if libubsan can't easily print those values into strings, it should just print or something similar for now. > Yes. I suspect adding support for _Decimal* shouldn't be hard, > what's needed is to find the place where the conversion from _Decimal > to integer is taking place and add similar code as is in convert.c. > Jakub says he's writing another testcase that tests various type > combination conversions and max/min values - so we'll get even more > coverage. Here is a testcase that (IMHO, not tested with your patch) should test various boundary cases that shouldn't result in undefined behavior. I've tried to keep it portable across various architectures, assumes primarily two's complement and (likely) only supports binary and decimal floating point formats. Seems _Decimal{32,64,128} is not convertible to/from int128 right now, so that is disabled in the test for now. Jakub --jTMWTj4UTAEmbWeb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="float-cast-overflow-3.c" Content-length: 8608 /* { dg-do run } */ /* { dg-options "-fsanitize=float-cast-overflow -fno-sanitize-recover" } */ /* FIXME: When _DecimalXX <-> {signed, unsigned} __int128 conversions are supported, -DBROKEN_DECIMAL_INT128 can be removed. */ /* { dg-additional-options "-DUSE_DFP -DBROKEN_DECIMAL_INT128" { target dfp } } */ #define CVTFN(type1, type2) \ __attribute__((noinline)) type1 \ cvt_##type1##_##type2 (type2 x) \ { \ return x; \ } typedef signed char sc; #define sc_MIN (-__SCHAR_MAX__ - 1) #define sc_MAX __SCHAR_MAX__ typedef unsigned char uc; #define uc_MIN 0 #define uc_MAX (2U * __SCHAR_MAX__ + 1U) typedef char c; #define c_MIN ((((char) -1) > (char) 0) ? uc_MIN : sc_MIN) #define c_MAX ((((char) -1) > (char) 0) ? uc_MAX : sc_MAX) typedef signed short ss; #define ss_MIN (-__SHRT_MAX__ - 1) #define ss_MAX __SHRT_MAX__ typedef unsigned short us; #define us_MIN 0 #define us_MAX (2U * __SHRT_MAX__ + 1U) typedef signed int si; #define si_MIN (-__INT_MAX__ - 1) #define si_MAX __INT_MAX__ typedef unsigned int ui; #define ui_MIN 0 #define ui_MAX (2U * __INT_MAX__ + 1U) typedef signed long sl; #define sl_MIN (-__LONG_MAX__ - 1L) #define sl_MAX __LONG_MAX__ typedef unsigned long ul; #define ul_MIN 0L #define ul_MAX (2UL * __LONG_MAX__ + 1UL) typedef signed long long sll; #define sll_MIN (-__LONG_LONG_MAX__ - 1LL) #define sll_MAX __LONG_LONG_MAX__ typedef unsigned long long ull; #define ull_MIN 0LL #define ull_MAX (2ULL * __LONG_LONG_MAX__ + 1ULL) #ifdef __SIZEOF_INT128__ typedef signed __int128 si128; # define si128_MAX \ ((signed __int128) ((((unsigned __int128) 1) \ << (__CHAR_BIT__ * __SIZEOF_INT128__ - 1)) - 1)) # define si128_MIN (-si128_MAX - 1) typedef unsigned __int128 ui128; #define ui128_MIN ((unsigned __int128) 0) #define ui128_MAX (((unsigned __int128) 2) * si128_MAX + 1) #endif #ifdef __SIZEOF_INT128__ # define CVTS128(type2) CVTFN (si128, type2) CVTFN (ui128, type2) #else # define CVTS128(type2) #endif #define CVTS(type2) \ CVTFN (sc, type2) CVTFN (c, type2) CVTFN (uc, type2) \ CVTFN (ss, type2) CVTFN (us, type2) \ CVTFN (si, type2) CVTFN (ui, type2) \ CVTFN (sl, type2) CVTFN (ul, type2) \ CVTFN (sll, type2) CVTFN (ull, type2) \ CVTS128 (type2) #ifdef __SIZEOF_INT128__ # define TWO ((unsigned __int128) 2) # define M1U ((unsigned __int128) -1) # define MAXS (__CHAR_BIT__ * __SIZEOF_INT128__) # define MAXT unsigned __int128 #else # define TWO 2ULL # define M1U -1ULL # define MAXS (__CHAR_BIT__ * __SIZEOF_LONG_LONG__) # define MAXT unsigned long long #endif typedef float f; #define f_RADIX 2 #define f_MANT_DIG __FLT_MANT_DIG__ #define f_MAX ((TWO << (f_MANT_DIG - 1)) - 1) typedef double d; #define d_RADIX 2 #define d_MANT_DIG __DBL_MANT_DIG__ #define d_MAX ((TWO << (d_MANT_DIG - 1)) - 1) typedef long double ld; #define ld_RADIX 2 #define ld_MANT_DIG __LDBL_MANT_DIG__ #define ld_MAX \ (ld_MANT_DIG > MAXS ? M1U : (TWO << (ld_MANT_DIG > MAXS \ ? 0 : ld_MANT_DIG - 1)) - 1) CVTS (f) CVTS (d) CVTS (ld) #ifdef __SIZEOF_FLOAT80__ typedef __float80 f80; # define f80_RADIX 2 # define f80_MANT_DIG 64 # define f80_MAX ((TWO << (d_MANT_DIG - 1)) - 1) CVTS (f80) #endif #ifdef __SIZEOF_FLOAT128__ typedef __float128 f128; # define f128_RADIX 2 # define f128_MANT_DIG 113 # define f128_MAX \ (f128_MANT_DIG > MAXS ? M1U : (TWO << (f128_MANT_DIG > MAXS \ ? 0 : f128_MANT_DIG - 1)) - 1) CVTS (f128) #endif #ifdef USE_DFP typedef _Decimal32 d32; # define d32_RADIX 10 # define d32_MANT_DIG __DEC32_MANT_DIG__ # if d32_MANT_DIG == 7 # define d32_MAX 9999999ULL # endif typedef _Decimal64 d64; # define d64_RADIX 10 # define d64_MANT_DIG __DEC64_MANT_DIG__ # if d64_MANT_DIG == 16 # define d64_MAX 9999999999999999ULL # endif typedef _Decimal128 d128; # define d128_RADIX 10 # define d128_MANT_DIG __DEC128_MANT_DIG__ # ifdef __SIZEOF_FLOAT128__ # if d128_MANT_DIG == 34 /* #define d128_MAX 1ed09bead87c0378d8e63ffffffff */ # define d128_MAX \ ((((unsigned __int128) 0x1ed09bead87c0) << 64) + 0x378d8e63ffffffffULL) # else # define d128_MAX M1U # endif # endif # ifdef BROKEN_DECIMAL_INT128 # undef CVTS128 # define CVTS128(type2) # endif CVTS (d32) CVTS (d64) CVTS (d128) #endif extern #ifdef __cplusplus "C" #endif void abort (); #define P(n) __builtin_printf ("%d\n", n) #define TEST(type1, type2) \ if (cvt_##type1##_##type2 (-0.5f) != 0) abort (); \ if (cvt_##type1##_##type2 (0.5f) != 0) abort (); \ if (cvt_##type1##_##type2 (-0.75f) != 0) abort (); \ if (cvt_##type1##_##type2 (0.75f) != 0) abort (); \ if (type1##_MIN) \ { \ /* For RADIX 2 type1##_MIN should be always */ \ /* exactly representable in type2. */ \ if (type2##_RADIX == 2 \ || type1##_MAX <= type2##_MAX) \ { \ if (cvt_##type1##_##type2 (type1##_MIN) \ != type1##_MIN) abort (); \ if (cvt_##type1##_##type2 ((type2) -0.75f \ + type1##_MIN) \ != type1##_MIN) abort (); \ } \ else \ { \ type2 min = type1##_MIN; \ /* tem could be below minimum here due to */ \ /* rounding. */ \ MAXT add = 1; \ while (add) \ { \ volatile type2 tem = type1##_MIN + (type1) add; \ if (tem != min) \ break; \ MAXT newadd = add * type2##_RADIX; \ if (newadd < add || newadd > type1##_MAX) \ add = 0; \ else \ add = newadd; \ } \ if (add) \ { \ MAXT newadd \ = (-(type1##_MIN + (type1) add)) % add; \ volatile type2 tem = type1##_MIN + (type1) newadd;\ volatile type2 tem2 = type1##_MIN + (type1) add; \ if (tem == tem2) \ add = newadd; \ else \ { \ newadd += add; \ if (newadd < add || newadd > type1##_MAX) \ add = 0; \ else \ { \ tem = type1##_MIN + (type1) newadd; \ if (tem == tem2) \ add = newadd; \ else \ add = 0; \ } \ } \ } \ if (add \ && cvt_##type1##_##type2 (type1##_MIN \ + (type1) add) \ != type1##_MIN + (type1) add) abort (); \ } \ } \ if (type1##_MAX <= type2##_MAX) \ { \ if (cvt_##type1##_##type2 (type1##_MAX) != type1##_MAX) \ abort (); \ volatile type2 tem = ((type2) 0.75f) + type1##_MAX; \ volatile type2 tem2 = ((type2) 1.0f) + type1##_MAX; \ if (tem < tem2 \ && cvt_##type1##_##type2 ((type2) 0.75f + type1##_MAX)\ != type1##_MAX) abort (); \ } \ else \ { \ type2 max = type1##_MAX; \ /* tem could be above maximum here due to rounding. */ \ MAXT sub = 1; \ while (sub) \ { \ volatile type2 tem = type1##_MAX - sub; \ if (tem != max) \ break; \ MAXT newsub = sub * type2##_RADIX; \ if (newsub < sub || newsub > type1##_MAX) \ sub = 0; \ else \ sub = newsub; \ } \ if (sub) \ { \ MAXT newsub = ((type1##_MAX - sub) % sub); \ volatile type2 tem = type1##_MAX - newsub; \ volatile type2 tem2 = type1##_MAX - sub; \ if (tem == tem2) \ sub = newsub; \ else \ { \ newsub += sub; \ if (newsub < sub || newsub > type1##_MAX) \ sub = 0; \ else \ { \ tem = type1##_MAX - newsub; \ if (tem == tem2) \ sub = newsub; \ else \ sub = 0; \ } \ } \ } \ if (sub \ && cvt_##type1##_##type2 (type1##_MAX - sub) \ != type1##_MAX - sub) abort (); \ } #ifdef __SIZEOF_INT128__ # define TESTS128(type2) TEST (si128, type2) TEST (ui128, type2) #else # define TESTS128(type2) #endif #define TESTS(type2) \ TEST (sc, type2) TEST (c, type2) TEST (uc, type2) \ TEST (ss, type2) TEST (us, type2) \ TEST (si, type2) TEST (ui, type2) \ TEST (sl, type2) TEST (ul, type2) \ TEST (sll, type2) TEST (ull, type2) \ TESTS128 (type2) int main () { TESTS (f) TESTS (d) TESTS (ld) #ifdef f80_MAX TESTS (f80) #endif #ifdef f128_MAX TESTS (f128) #endif #ifdef BROKEN_DECIMAL_INT128 # undef TESTS128 # define TESTS128(type2) # undef TWO # undef M1U # undef MAXS # undef MAXT # define TWO 2ULL # define M1U -1ULL # define MAXS (__CHAR_BIT__ * __SIZEOF_LONG_LONG__) # define MAXT unsigned long long #endif #ifdef d32_MAX TESTS (d32) #endif #ifdef d64_MAX TESTS (d64) #endif #ifdef d128_MAX TESTS (d128) #endif return 0; } --jTMWTj4UTAEmbWeb--