From patchwork Fri May 5 20:53:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 90581 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp682976vqo; Fri, 5 May 2023 13:53:56 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6XXRo6FFmm17/fRBxh9jFcxwbcx30Bb9nEp+6RWQIQFEqPgNTyENaXWTmNCh+x6nB+kDzi X-Received: by 2002:a05:6402:4303:b0:50d:83d4:6174 with SMTP id m3-20020a056402430300b0050d83d46174mr1334872edc.12.1683320036164; Fri, 05 May 2023 13:53:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683320036; cv=none; d=google.com; s=arc-20160816; b=Q1vkhhr+MTlQFMknWIjKejzeqUBNjdtbreCD0NvWtGGujFWlAAOqGUuXFlRa5Rl1xt iMDA72Ff9TXyILptQuQOJafl92qoLP6/jFb3L/p5EpRYizv+v3bpeljjYpdmrDtfvzmp J0Bzlb5LGdLQVM+/KrbdV7gI3oOHIZvq6BRFC5If9gIIWxQs7aqlgdqvGr/Jt69Y690E yg9Wm204vzOQxohdOdwhxOlJR+Vtdgy+hdaPMtfpk6yMOnbC0EkUDHSi/jqW40ew2A2G rTkXUiDVPhX3QTfId9CdZidh7soB+j/BNUs2L1XODUY0/vqDBrS9wNyzg4BrXVJi7g4s ALkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-disposition:mime-version:message-id:subject:cc:to:date :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=fu08A5cUkNx+pA8VeMIe+HYHTdoqlVzJUYkNl6Tmc/k=; b=YGdc7jM7npi6qTHwt4HdpdvEP/u2AV4bC7NcCZWbVbeaOO2aqyWGARAGUTDatpNDol gW8iLJ6byLSXP7jXBxeYu85T1/JKQysA9ki47ud52rEF/hPvbkGRAXeJ/wNFyS7HiUMx sy+Ul2t68MJ9pRA6v7aOWeYEhf1v4tA9aUcqAh7aP6tUTT9SCwXiM0Qy4t1PDPrLY8t8 o1JBdN60gNXjXbPeiX6gYGnhtaTu0cSu8OIVUC66n8ZXFu966MTtfQqr1EYYbMPs6mV1 38pig+GlABqJLmKwkNqlSJrQiANf/mifUPLf1SPNoaUAHod391gpU2eKqsZTERTvhaBo nDXw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=csPTJyEO; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id y6-20020aa7d506000000b0050be186932dsi4976255edq.658.2023.05.05.13.53.55 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 May 2023 13:53:56 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=csPTJyEO; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C7DDA3857353 for ; Fri, 5 May 2023 20:53:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C7DDA3857353 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1683320034; bh=fu08A5cUkNx+pA8VeMIe+HYHTdoqlVzJUYkNl6Tmc/k=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=csPTJyEOF1tWdr+xjQWtoe0U5efyz0K0ApYfqThpiYmkK5qGpaTMkKpAEeHNCDb6N hcSDW5qkajw37eNm6gXQt2fpEllfyVOpbwtHXg8wA584ufWZ64PBh6NNK6+iE/bJXe gWFqhDjnfzVmKnXGPz8DW+0BjoSE2QgGqpY3L7WI= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 69D8C3858D33 for ; Fri, 5 May 2023 20:53:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 69D8C3858D33 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-515-wrEPCcsePkKo2NLquDPsSw-1; Fri, 05 May 2023 16:53:08 -0400 X-MC-Unique: wrEPCcsePkKo2NLquDPsSw-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8F2DC101A531 for ; Fri, 5 May 2023 20:53:08 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.194.156]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 526A4492B00; Fri, 5 May 2023 20:53:08 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 345Kr6ST3558209 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 5 May 2023 22:53:06 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 345Kr5N03558208; Fri, 5 May 2023 22:53:05 +0200 Date: Fri, 5 May 2023 22:53:05 +0200 To: Aldy Hernandez Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] gimple-range-op: Improve handling of sin/cos ranges Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1765088990331808648?= X-GMAIL-MSGID: =?utf-8?q?1765088990331808648?= Hi! Similarly to the earlier sqrt patch, this patch attempts to improve sin/cos ranges. As the functions are periodic, for the reverse range there is not much we can do (but I've discovered I forgot to take into account the boundary ulps for the discovery of impossible result ranges). For fold_range, we can do something only if the range is narrow enough (narrower than 2*pi). The patch computes the value of the functions (taking ulps into account) and also computes the derivative to find out if the function is growing or declining on the boundaries and from that it figures out if the result range should be [min (fn (lb), fn (ub)), max (fn (lb), fn (ub))] or if it needs to be extended to 1 (actually using +Inf) and/or -1 (actually using -Inf) because there must be a local minimum and/or maximum in the range. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2023-05-05 Jakub Jelinek * real.h (dconst_pi): Define. (dconst_e_ptr): Formatting fix. (dconst_pi_ptr): Declare. * real.cc (dconst_pi_ptr): New function. * gimple-range-op.cc (cfn_sincos::fold_range): Intersect the generic boundaries range with range computed from sin/cos of the particular bounds if the argument range is shorter than 2*pi. (cfn_sincos::op1_range): Take bulps into account when determining which result ranges are always invalid or behave like known NAN. * gcc.dg/tree-ssa/range-sincos-2.c: New test. Jakub --- gcc/real.h.jj 2023-04-19 09:33:59.434350121 +0200 +++ gcc/real.h 2023-05-05 16:36:35.606611170 +0200 @@ -480,9 +480,13 @@ extern REAL_VALUE_TYPE dconstninf; #define dconst_sixth() (*dconst_sixth_ptr ()) #define dconst_ninth() (*dconst_ninth_ptr ()) #define dconst_sqrt2() (*dconst_sqrt2_ptr ()) +#define dconst_pi() (*dconst_pi_ptr ()) /* Function to return the real value special constant 'e'. */ -extern const REAL_VALUE_TYPE * dconst_e_ptr (void); +extern const REAL_VALUE_TYPE *dconst_e_ptr (void); + +/* Function to return the real value special constant 'pi'. */ +extern const REAL_VALUE_TYPE *dconst_pi_ptr (void); /* Returns a cached REAL_VALUE_TYPE corresponding to 1/n, for various n. */ extern const REAL_VALUE_TYPE *dconst_third_ptr (void); --- gcc/real.cc.jj 2023-04-20 09:36:09.066376175 +0200 +++ gcc/real.cc 2023-05-05 16:39:25.244201299 +0200 @@ -2475,6 +2475,26 @@ dconst_e_ptr (void) return &value; } +/* Returns the special REAL_VALUE_TYPE corresponding to 'pi'. */ + +const REAL_VALUE_TYPE * +dconst_pi_ptr (void) +{ + static REAL_VALUE_TYPE value; + + /* Initialize mathematical constants for constant folding builtins. + These constants need to be given to at least 160 bits precision. */ + if (value.cl == rvc_zero) + { + auto_mpfr m (SIGNIFICAND_BITS); + mpfr_set_si (m, -1, MPFR_RNDN); + mpfr_acos (m, m, MPFR_RNDN); + real_from_mpfr (&value, m, NULL_TREE, MPFR_RNDN); + + } + return &value; +} + /* Returns a cached REAL_VALUE_TYPE corresponding to 1/n, for various n. */ #define CACHED_FRACTION(NAME, N) \ --- gcc/gimple-range-op.cc.jj 2023-05-05 16:02:48.174419009 +0200 +++ gcc/gimple-range-op.cc 2023-05-05 19:44:27.292304968 +0200 @@ -633,6 +633,98 @@ public: } if (!lh.maybe_isnan () && !lh.maybe_isinf ()) r.clear_nan (); + + unsigned ulps + = targetm.libm_function_max_error (m_cfn, TYPE_MODE (type), false); + if (ulps == ~0U) + return true; + REAL_VALUE_TYPE lb = lh.lower_bound (); + REAL_VALUE_TYPE ub = lh.upper_bound (); + REAL_VALUE_TYPE diff; + real_arithmetic (&diff, MINUS_EXPR, &ub, &lb); + if (!real_isfinite (&diff)) + return true; + REAL_VALUE_TYPE pi = dconst_pi (); + REAL_VALUE_TYPE pix2; + real_arithmetic (&pix2, PLUS_EXPR, &pi, &pi); + // We can only try to narrow the range further if ub-lb < 2*pi. + if (!real_less (&diff, &pix2)) + return true; + REAL_VALUE_TYPE lb_lo, lb_hi, ub_lo, ub_hi; + REAL_VALUE_TYPE lb_deriv_lo, lb_deriv_hi, ub_deriv_lo, ub_deriv_hi; + if (!frange_mpfr_arg1 (&lb_lo, &lb_hi, + m_cfn == CFN_SIN ? mpfr_sin : mpfr_cos, lb, + type, ulps) + || !frange_mpfr_arg1 (&ub_lo, &ub_hi, + m_cfn == CFN_SIN ? mpfr_sin : mpfr_cos, ub, + type, ulps) + || !frange_mpfr_arg1 (&lb_deriv_lo, &lb_deriv_hi, + m_cfn == CFN_SIN ? mpfr_cos : mpfr_sin, lb, + type, 0) + || !frange_mpfr_arg1 (&ub_deriv_lo, &ub_deriv_hi, + m_cfn == CFN_SIN ? mpfr_cos : mpfr_sin, ub, + type, 0)) + return true; + if (m_cfn == CFN_COS) + { + // Derivative of cos is -sin, so negate. + lb_deriv_lo.sign ^= 1; + lb_deriv_hi.sign ^= 1; + ub_deriv_lo.sign ^= 1; + ub_deriv_hi.sign ^= 1; + } + + if (real_less (&lb_lo, &ub_lo)) + lb = lb_lo; + else + lb = ub_lo; + if (real_less (&lb_hi, &ub_hi)) + ub = ub_hi; + else + ub = lb_hi; + + // The range between the function result on the boundaries may need + // to be extended to +1 (+Inf) or -1 (-Inf) or both depending on the + // derivative or length of the argument range (diff). + + // First handle special case, where the derivative has different signs, + // so the bound must be roughly -1 or +1. + if (real_isneg (&lb_deriv_lo) != real_isneg (&lb_deriv_hi)) + { + if (real_isneg (&lb_lo)) + lb = dconstninf; + else + ub = dconstinf; + } + if (real_isneg (&ub_deriv_lo) != real_isneg (&ub_deriv_hi)) + { + if (real_isneg (&ub_lo)) + lb = dconstninf; + else + ub = dconstinf; + } + + // If derivative at lower_bound and upper_bound have the same sign, + // the function grows or declines on the whole range if diff < pi, so + // [lb, ub] is correct, and if diff >= pi the result range must include + // both the minimum and maximum. + if (real_isneg (&lb_deriv_lo) == real_isneg (&ub_deriv_lo)) + { + if (!real_less (&diff, &pi)) + return true; + } + // If function declines at lower_bound and grows at upper_bound, + // the result range must include the minimum, so set lb to -Inf. + else if (real_isneg (&lb_deriv_lo)) + lb = dconstninf; + // If function grows at lower_bound and declines at upper_bound, + // the result range must include the maximum, so set ub to +Inf. + else + ub = dconstinf; + frange r2; + r2.set (type, lb, ub); + r2.flush_denormals_to_zero (); + r.intersect (r2); return true; } virtual bool op1_range (frange &r, tree type, @@ -651,31 +743,42 @@ public: } // Results outside of [-1.0, +1.0] are impossible. - REAL_VALUE_TYPE lb = lhs.lower_bound (); - REAL_VALUE_TYPE ub = lhs.upper_bound (); - if (real_less (&ub, &dconstm1) || real_less (&dconst1, &lb)) + unsigned bulps + = targetm.libm_function_max_error (m_cfn, TYPE_MODE (type), true); + if (bulps != ~0U) { - if (!lhs.maybe_isnan ()) - r.set_undefined (); - else - /* If lhs could be NAN and finite result is impossible, - the range is like lhs.known_isnan () above, - [-INF,-INF][+INF,+INF] U +-NAN. */ - r.set_varying (type); - return true; + const REAL_VALUE_TYPE &lb = lhs.lower_bound (); + const REAL_VALUE_TYPE &ub = lhs.upper_bound (); + REAL_VALUE_TYPE m1 = dconstm1; + REAL_VALUE_TYPE p1 = dconst1; + while (bulps--) + { + frange_nextafter (TYPE_MODE (type), m1, dconstninf); + frange_nextafter (TYPE_MODE (type), p1, dconstinf); + } + if (real_less (&ub, &m1) || real_less (&p1, &lb)) + { + if (!lhs.maybe_isnan ()) + r.set_undefined (); + else + /* If lhs could be NAN and finite result is impossible, + the range is like lhs.known_isnan () above, + [-INF,-INF][+INF,+INF] U +-NAN. */ + r.set_varying (type); + return true; + } } if (!lhs.maybe_isnan ()) { // If NAN is not valid result, the input cannot include either // a NAN nor a +-INF. - lb = real_min_representable (type); - ub = real_max_representable (type); + REAL_VALUE_TYPE lb = real_min_representable (type); + REAL_VALUE_TYPE ub = real_max_representable (type); r.set (type, lb, ub, nan_state (false, false)); - return true; } - - r.set_varying (type); + else + r.set_varying (type); return true; } private: --- gcc/testsuite/gcc.dg/tree-ssa/range-sincos-2.c.jj 2023-05-05 19:54:11.705064161 +0200 +++ gcc/testsuite/gcc.dg/tree-ssa/range-sincos-2.c 2023-05-05 20:13:11.859961631 +0200 @@ -0,0 +1,34 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-evrp -fno-thread-jumps" } + +void use (double); +void link_error (); + +void +foo (double x) +{ + double y; + if (x >= 0.5 && x <= 1.3) + { + y = __builtin_sin (x); + if (y < 0.45 || y > 0.97) + link_error (); + use (y); + } + if (x >= 0.5 && x < 1.75) + { + y = __builtin_sin (x); + if (y < 0.45 || y > 1.05) + link_error (); + use (y); + } + if (x >= -1.57 && x <= 1.57) + { + y = __builtin_cos (x); + if (y < 0.0007 || y > 1.05) + link_error (); + use (y); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" { target { { *-*-linux* } && { glibc } } } } }