From patchwork Sat Sep 14 00:40:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1162277 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-509001-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="fuIxEe05"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46VYZd513pz9sN1 for ; Sat, 14 Sep 2019 10:40:38 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; q=dns; s=default; b=xAh/3SB5oAmeH4IDBy5QjtrCw0P7x Z1s0G2lB258y/hvl/RIR72xi7nH3q4uC70zEz/J7VDlxSmyRfx0nFLesSys3kZ7q dpqSbtHs9ESrQ1bfTD0fupCyxOGyoeFsboECvZqDwp5pKovBcvy72AzQ6niHgmcd lOD3/bRp2NcldI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; s=default; bh=rObUY+dgKIs19up2pGDdvQKD1Dw=; b=fuI xEe05F2G/dbaClvbNYJqZduaJ0IYXl5mx7aBKOwFwHQ+FMDVvWKMXKKRIqrTfMZG 6Bg/3m/NKAhtWx0NfuBfU3a4uHMlwepYsgbisuTdLl9nH6jcIaepdRTIOKceoKjJ Qu4Yg0YIc4UyF7rfaP2iAYVtttLfPqIOhdXgY344= Received: (qmail 23318 invoked by alias); 14 Sep 2019 00:40:29 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 23303 invoked by uid 89); 14 Sep 2019 00:40:29 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-6.8 required=5.0 tests=AWL, BAYES_05, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=UD:c.jj, UD:jj, matchpd, UD:pd 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; Sat, 14 Sep 2019 00:40:27 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 30E593091761; Sat, 14 Sep 2019 00:40:26 +0000 (UTC) Received: from laptop.zalov.cz (ovpn-116-23.ams2.redhat.com [10.36.116.23]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 526065D6B0; Sat, 14 Sep 2019 00:40:25 +0000 (UTC) Received: from laptop.zalov.cz (localhost [127.0.0.1]) by laptop.zalov.cz (8.15.2/8.15.2) with ESMTP id x8E0eJmC010563; Sat, 14 Sep 2019 02:40:20 +0200 Received: (from jakub@localhost) by laptop.zalov.cz (8.15.2/8.15.2/Submit) id x8E0eFkk010562; Sat, 14 Sep 2019 02:40:15 +0200 Date: Sat, 14 Sep 2019 02:40:14 +0200 From: Jakub Jelinek To: Richard Biener Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix up sqrt(x) < c and sqrt(x) >= c match.pd folding (PR tree-optimization/91734) Message-ID: <20190914004014.GE25273@laptop.zalov.cz> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.6.1 (2016-04-27) X-IsSubscribed: yes Hi! As mentioned in the PR, the sqrt (x) < c optimization into x < c*c sometimes breaks the boundary case, if c2=c*c is inexact then in some cases we need to optimize it into x <= c*c rather than x < c*c. The original bugreport is when c is small and c2 is 0.0, then obviously we need <= 0.0 rather than < 0.0, but the testcase includes another example where it makes a difference, plus has a >= testcase too. Bootstrapped/regtested on powerpc64le-linux, ok for trunk? 2019-09-13 Jakub Jelinek PR tree-optimization/91734 * generic-match-head.c: Include fold-const-call.h. * match.pd (sqrt(x) < c, sqrt(x) >= c): Check the boundary value and in case inexact computation of c*c affects comparison of the boundary, turn LT_EXPR into LE_EXPR or GE_EXPR into GT_EXPR. * gcc.dg/pr91734.c: New test. Jakub --- gcc/generic-match-head.c.jj 2019-07-20 21:02:09.296821929 +0200 +++ gcc/generic-match-head.c 2019-09-12 10:52:33.091366624 +0200 @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. #include "cgraph.h" #include "vec-perm-indices.h" #include "fold-const.h" +#include "fold-const-call.h" #include "stor-layout.h" #include "tree-dfa.h" #include "builtins.h" --- gcc/match.pd.jj 2019-09-11 21:50:54.933504293 +0200 +++ gcc/match.pd 2019-09-12 11:12:11.150987786 +0200 @@ -3541,56 +3541,71 @@ (define_operator_list COND_TERNARY if x is negative or NaN. Due to -funsafe-math-optimizations, the results for other x follow from natural arithmetic. */ (cmp @0 @1))) - (if (cmp == GT_EXPR || cmp == GE_EXPR) + (if (cmp == LT_EXPR || cmp == LE_EXPR || cmp == GT_EXPR || cmp == GE_EXPR) (with { - REAL_VALUE_TYPE c2; + REAL_VALUE_TYPE c2; + enum tree_code ncmp = cmp; real_arithmetic (&c2, MULT_EXPR, &TREE_REAL_CST (@1), &TREE_REAL_CST (@1)); real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2); + /* See PR91734: if c2 is inexact and sqrt(c2) < c (or sqrt(c2) >= c), + then change LT_EXPR into LE_EXPR or GE_EXPR into GT_EXPR. */ + if ((cmp == LT_EXPR || cmp == GE_EXPR) && !REAL_VALUE_ISINF (c2)) + { + tree c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0), + build_real (TREE_TYPE (@0), c2)); + if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST) + ncmp = ERROR_MARK; + else if (real_less (&TREE_REAL_CST (c3), &TREE_REAL_CST (@1))) + ncmp = cmp == LT_EXPR ? LE_EXPR : GT_EXPR; + } } - (if (REAL_VALUE_ISINF (c2)) - /* sqrt(x) > y is x == +Inf, when y is very large. */ - (if (HONOR_INFINITIES (@0)) - (eq @0 { build_real (TREE_TYPE (@0), c2); }) - { constant_boolean_node (false, type); }) - /* sqrt(x) > c is the same as x > c*c. */ - (cmp @0 { build_real (TREE_TYPE (@0), c2); })))) - (if (cmp == LT_EXPR || cmp == LE_EXPR) - (with - { - REAL_VALUE_TYPE c2; - real_arithmetic (&c2, MULT_EXPR, - &TREE_REAL_CST (@1), &TREE_REAL_CST (@1)); - real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2); - } - (if (REAL_VALUE_ISINF (c2)) - (switch - /* sqrt(x) < y is always true, when y is a very large - value and we don't care about NaNs or Infinities. */ - (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0)) - { constant_boolean_node (true, type); }) - /* sqrt(x) < y is x != +Inf when y is very large and we - don't care about NaNs. */ - (if (! HONOR_NANS (@0)) - (ne @0 { build_real (TREE_TYPE (@0), c2); })) - /* sqrt(x) < y is x >= 0 when y is very large and we - don't care about Infinities. */ - (if (! HONOR_INFINITIES (@0)) - (ge @0 { build_real (TREE_TYPE (@0), dconst0); })) - /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */ - (if (GENERIC) - (truth_andif - (ge @0 { build_real (TREE_TYPE (@0), dconst0); }) - (ne @0 { build_real (TREE_TYPE (@0), c2); })))) - /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */ - (if (! HONOR_NANS (@0)) - (cmp @0 { build_real (TREE_TYPE (@0), c2); }) - /* sqrt(x) < c is the same as x >= 0 && x < c*c. */ - (if (GENERIC) - (truth_andif - (ge @0 { build_real (TREE_TYPE (@0), dconst0); }) - (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))))))) + (if (cmp == GT_EXPR || cmp == GE_EXPR) + (if (REAL_VALUE_ISINF (c2)) + /* sqrt(x) > y is x == +Inf, when y is very large. */ + (if (HONOR_INFINITIES (@0)) + (eq @0 { build_real (TREE_TYPE (@0), c2); }) + { constant_boolean_node (false, type); }) + /* sqrt(x) > c is the same as x > c*c. */ + (if (ncmp != ERROR_MARK) + (if (ncmp == GE_EXPR) + (ge @0 { build_real (TREE_TYPE (@0), c2); }) + (gt @0 { build_real (TREE_TYPE (@0), c2); })))) + /* else if (cmp == LT_EXPR || cmp == LE_EXPR) */ + (if (REAL_VALUE_ISINF (c2)) + (switch + /* sqrt(x) < y is always true, when y is a very large + value and we don't care about NaNs or Infinities. */ + (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0)) + { constant_boolean_node (true, type); }) + /* sqrt(x) < y is x != +Inf when y is very large and we + don't care about NaNs. */ + (if (! HONOR_NANS (@0)) + (ne @0 { build_real (TREE_TYPE (@0), c2); })) + /* sqrt(x) < y is x >= 0 when y is very large and we + don't care about Infinities. */ + (if (! HONOR_INFINITIES (@0)) + (ge @0 { build_real (TREE_TYPE (@0), dconst0); })) + /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */ + (if (GENERIC) + (truth_andif + (ge @0 { build_real (TREE_TYPE (@0), dconst0); }) + (ne @0 { build_real (TREE_TYPE (@0), c2); })))) + /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */ + (if (ncmp != ERROR_MARK && ! HONOR_NANS (@0)) + (if (ncmp == LT_EXPR) + (lt @0 { build_real (TREE_TYPE (@0), c2); }) + (le @0 { build_real (TREE_TYPE (@0), c2); })) + /* sqrt(x) < c is the same as x >= 0 && x < c*c. */ + (if (ncmp != ERROR_MARK && GENERIC) + (if (ncmp == LT_EXPR) + (truth_andif + (ge @0 { build_real (TREE_TYPE (@0), dconst0); }) + (lt @0 { build_real (TREE_TYPE (@0), c2); })) + (truth_andif + (ge @0 { build_real (TREE_TYPE (@0), dconst0); }) + (le @0 { build_real (TREE_TYPE (@0), c2); }))))))))))) /* Transform sqrt(x) cmp sqrt(y) -> x cmp y. */ (simplify (cmp (sq @0) (sq @1)) --- gcc/testsuite/gcc.dg/pr91734.c.jj 2019-09-12 10:52:33.094366596 +0200 +++ gcc/testsuite/gcc.dg/pr91734.c 2019-09-12 10:49:10.000000000 +0200 @@ -0,0 +1,34 @@ +/* PR tree-optimization/91734 */ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-additional-options "-ffast-math -O2 -std=gnu99" } */ + +__attribute__((noipa)) int +foo (float x) +{ + return __builtin_sqrtf (x) < __FLT_MIN__; +} + +__attribute__((noipa)) int +bar (float x) +{ + return __builtin_sqrtf (x) < 0x1.2dd3d0p-65f; +} + +__attribute__((noipa)) int +baz (float x) +{ + return __builtin_sqrtf (x) >= 0x1.2dd3d0p-65f; +} + +int +main () +{ + if (!foo (0.0f)) + __builtin_abort (); + if (!bar (0x1.63dbc0p-130f)) + __builtin_abort (); + if (baz (0x1.63dbc0p-130f)) + __builtin_abort (); + return 0; +}