From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30045 invoked by alias); 16 May 2014 07:37:07 -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 30025 invoked by uid 89); 16 May 2014 07:37:06 -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; Fri, 16 May 2014 07:37:04 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s4G7b0RX006519 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 16 May 2014 03:37:01 -0400 Received: from tucnak.zalov.cz (ovpn-116-116.ams2.redhat.com [10.36.116.116]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s4G7awGs026535 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 16 May 2014 03:37:00 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.14.8/8.14.7) with ESMTP id s4G7au6e017070; Fri, 16 May 2014 09:36:57 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.14.8/8.14.8/Submit) id s4G7asig017069; Fri, 16 May 2014 09:36:54 +0200 Date: Fri, 16 May 2014 07:37:00 -0000 From: Jakub Jelinek To: "Joseph S. Myers" Cc: Marek Polacek , GCC Patches Subject: Re: [PATCH] Implement -fsanitize=float-cast-overflow Message-ID: <20140516073654.GS10386@tucnak.redhat.com> Reply-To: Jakub Jelinek References: <20140513170801.GG2663@redhat.com> <20140514113839.GE10386@tucnak.redhat.com> <20140515190929.GQ10386@tucnak.redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes X-SW-Source: 2014-05/txt/msg01242.txt.bz2 On Thu, May 15, 2014 at 09:29:44PM +0000, Joseph S. Myers wrote: > On Thu, 15 May 2014, Jakub Jelinek wrote: > > > But I think we can't use decimal_real_from_string, we'd need a variant > > of that function that would allow specification of the rounding mode > > My point is that you can use "%.*RUe" or "%.*RDe" formats (for max and min > respectively), with an appropriate precision, and let MPFR do the rounding > to an appropriate number of decimal digits in the right direction (to > produce a value that's exactly representable in the relevant DFP type, as > long as it's in range). You are right, that seems to work. So new incremental patch. BTW, for IBM long double __int128_t f3 (long double x) { return x; } the u>= { -170141183460469231731687303715884105728.0 + -4194304.0 } check is actually imprecise, while all correct long double values will be properly accepted, if high double is exactly -170141183460469231731687303715884105728.0 and low double is in [-1.0, -4194304.0), then the unspecified conversion will not be diagnosed, but I'm afraid there is nothing we can (easily) do about it, because { -170141183460469231731687303715884105728.0 + -1.0 }, while representable in IBM long double, is not representable in our REAL_VALUE_TYPE, because we assume fixed precision, while IBM long double has variable. Guess the combination of IBM long double and __int128_t (for long long it is still ok) is rare enough that we don't need to care about it (alternative would be e.g. to compare against addition of those two numbers with some optimization barrier/volatile that would avoid it from being optimized into a single long double number. --- gcc/convert.c +++ gcc/convert.c @@ -851,6 +851,8 @@ expr = save_expr (expr); tree check = ubsan_instrument_float_cast (loc, type, expr); expr = build1 (FIX_TRUNC_EXPR, type, expr); + if (check == NULL) + return expr; return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr); } else --- gcc/ubsan.c +++ gcc/ubsan.c @@ -47,6 +47,8 @@ #include "asan.h" #include "gimplify-me.h" #include "intl.h" +#include "realmpfr.h" +#include "dfp.h" /* Map from a tree to a VAR_DECL tree. */ @@ -903,17 +905,95 @@ ubsan_instrument_float_cast (location_t loc, tree type, tree expr) { tree expr_type = TREE_TYPE (expr); - tree t, tt, fn; + tree t, tt, fn, min, max; + enum machine_mode mode = TYPE_MODE (expr_type); + int prec = TYPE_PRECISION (type); + bool uns_p = TYPE_UNSIGNED (type); - tree min = TYPE_MIN_VALUE (type); - tree max = TYPE_MAX_VALUE (type); - /* Add/subtract 1.0 so we can avoid truncating the value of EXPR. */ - min = fold_build2 (MINUS_EXPR, expr_type, - build_real_from_int_cst (expr_type, min), - build_one_cst (expr_type)); - max = fold_build2 (PLUS_EXPR, expr_type, - build_real_from_int_cst (expr_type, max), - build_one_cst (expr_type)); + /* Float to integer conversion first truncates toward zero, so + even signed char c = 127.875f; is not problematic. + Therefore, we should complain only if EXPR is unordered or smaller + or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than + TYPE_MAX_VALUE + 1.0. */ + if (REAL_MODE_FORMAT (mode)->b == 2) + { + /* For maximum, TYPE_MAX_VALUE might not be representable + in EXPR_TYPE, e.g. if TYPE is 64-bit long long and + EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is + either representable or infinity. */ + REAL_VALUE_TYPE maxval = dconst1; + SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p); + real_convert (&maxval, mode, &maxval); + max = build_real (expr_type, maxval); + + /* For unsigned, assume -1.0 is always representable. */ + if (uns_p) + min = build_minus_one_cst (expr_type); + else + { + /* TYPE_MIN_VALUE is generally representable (or -inf), + but TYPE_MIN_VALUE - 1.0 might not be. */ + REAL_VALUE_TYPE minval = dconstm1, minval2; + SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1); + real_convert (&minval, mode, &minval); + real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1); + real_convert (&minval2, mode, &minval2); + if (real_compare (EQ_EXPR, &minval, &minval2) + && !real_isinf (&minval)) + { + /* If TYPE_MIN_VALUE - 1.0 is not representable and + rounds to TYPE_MIN_VALUE, we need to subtract + more. As REAL_MODE_FORMAT (mode)->p is the number + of base digits, we want to subtract a number that + will be 1 << (REAL_MODE_FORMAT (mode)->p - 1) + times smaller than minval. */ + minval2 = dconst1; + gcc_assert (prec > REAL_MODE_FORMAT (mode)->p); + SET_REAL_EXP (&minval2, + REAL_EXP (&minval2) + prec - 1 + - REAL_MODE_FORMAT (mode)->p + 1); + real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2); + real_convert (&minval2, mode, &minval2); + } + min = build_real (expr_type, minval2); + } + } + else if (REAL_MODE_FORMAT (mode)->b == 10) + { + /* For _Decimal128 up to 34 decimal digits, - sign, + dot, e, exponent. */ + char buf[64]; + mpfr_t m; + int p = REAL_MODE_FORMAT (mode)->p; + REAL_VALUE_TYPE maxval, minval; + + /* Use mpfr_snprintf rounding to compute the smallest + representable decimal number greater or equal than + 1 << (prec - !uns_p). */ + mpfr_init2 (m, prec + 2); + mpfr_set_ui_2exp (m, 1, prec - !uns_p, GMP_RNDN); + mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m); + decimal_real_from_string (&maxval, buf); + max = build_real (expr_type, maxval); + + /* For unsigned, assume -1.0 is always representable. */ + if (uns_p) + min = build_minus_one_cst (expr_type); + else + { + /* Use mpfr_snprintf rounding to compute the largest + representable decimal number less or equal than + (-1 << (prec - 1)) - 1. */ + mpfr_set_si_2exp (m, -1, prec - 1, GMP_RNDN); + mpfr_sub_ui (m, m, 1, GMP_RNDN); + mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m); + decimal_real_from_string (&minval, buf); + min = build_real (expr_type, minval); + } + mpfr_clear (m); + } + else + return NULL_TREE; if (flag_sanitize_undefined_trap_on_error) fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); Jakub