From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 718083858C52 for ; Fri, 11 Nov 2022 10:01:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 718083858C52 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668160903; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+3u+iNWZ+hsrMubX40VfPBnNYBJ7bd4uBPaI/VW/dss=; b=hHqx1qB0vfizjCr3s2BmF0TlCzjS/Yf3+CIcNfY/Lm34kg/B0Ddz7WtblRZZ53+vtTM8bz ZsRPcxk9BRU6+ox4s3eQcKWF7uWra63TV5V3pgvxgNx9ffQjju+FJ/GlxN+1hq5NSOwqJH qG3NeqHnLMDxukozHuRO17cGPZgbg6U= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-672-gBZfQYA1MQegG5P0_AFVlA-1; Fri, 11 Nov 2022 05:01:41 -0500 X-MC-Unique: gBZfQYA1MQegG5P0_AFVlA-1 Received: by mail-wm1-f70.google.com with SMTP id bg21-20020a05600c3c9500b003c2acbff422so3569189wmb.0 for ; Fri, 11 Nov 2022 02:01:41 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+3u+iNWZ+hsrMubX40VfPBnNYBJ7bd4uBPaI/VW/dss=; b=Y47/VU0VbtzwjTizJ9n/fkiudcYBzXU4xTFQtgcrS3WwtJipD/F/82mDd3mFJZh9Ir ZvCQowfAUPpbgpMCy5bQ9HfCmCjfpf/RD+9qq/L4KVwrT2mCch8935BdO3KChJSe5DkL QLdMEoqajKBABfAJHbOA5oIIVzR2qvt/L28WoeCkXo2OfINRYDwbjBmnDWYbwRijfcc6 SB+42+6LYFptLawZMRDYRWmdFktEq4qQu+UuL6YHCKu1/IX2I85w78Zn0UTBSxaOY41y GT0mjE4Raw6vzBc8ca6F8x5qedGUkxZsU37rExNZSMA8jzWBP/XiII6L8z2pInVCDYUw oy8A== X-Gm-Message-State: ANoB5pmRwceUIj4nxwWYghS7eie+jEa8nucMWodEy6JxBrBxX30K2SWt EUV1jiK2/ZfYrBguHwRq9ulIOCLR4ggyoPBgXwq25QjQ6A95xJ8ay8nsVjn4RVy0XF9NA76Qnw2 jx1Niw1A4XIRDK+mlXA== X-Received: by 2002:a05:600c:b41:b0:3b3:3256:647 with SMTP id k1-20020a05600c0b4100b003b332560647mr698583wmr.197.1668160900460; Fri, 11 Nov 2022 02:01:40 -0800 (PST) X-Google-Smtp-Source: AA0mqf671PwC8v5L5kRyXbmxg113poWzN2xn9SSf6BY8UEWts7Pn3GWz6ApsrNjwbUSHLYxlL9cyAg== X-Received: by 2002:a05:600c:b41:b0:3b3:3256:647 with SMTP id k1-20020a05600c0b4100b003b332560647mr698572wmr.197.1668160900153; Fri, 11 Nov 2022 02:01:40 -0800 (PST) Received: from [192.168.1.2] ([139.47.33.22]) by smtp.gmail.com with ESMTPSA id f20-20020a05600c155400b003c6f3e5ba42sm9601056wmg.46.2022.11.11.02.01.39 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 11 Nov 2022 02:01:39 -0800 (PST) Message-ID: <91a2e8c2-c846-6e8a-952e-d497db2fed50@redhat.com> Date: Fri, 11 Nov 2022 11:01:38 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.1 Subject: Re: [PATCH] range-op: Implement floating point multiplication fold_range [PR107569] To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org References: <7304acea-b8bb-c930-546a-db6e3b3ff96b@redhat.com> From: Aldy Hernandez In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-5.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 11/10/22 20:20, Jakub Jelinek wrote: > On Thu, Nov 10, 2022 at 03:50:47PM +0100, Aldy Hernandez wrote: >>> @@ -1908,6 +1910,123 @@ class foperator_minus : public range_ope >>> } >>> } fop_minus; >>> +/* Wrapper around frange_arithmetics, that computes the result >>> + if inexact rounded to both directions. Also, if one of the >>> + operands is +-0.0 and another +-INF, return +-0.0 rather than >>> + NAN. */ >> >> s/frange_arithmetics/frange_arithmetic/ >> >> Also, would you mind written a little blurb about why it's necessary not to >> compute INF*0.0 as NAN. I assume it's because you're using it for the cross >> product and you'll set maybe_nan separately, but it's nice to spell it out. > > This made me think about it some more and I'll need to play around with it > some more, perhaps the right thing is similarly to what I've attached for > division to handle special cases upfront and call frange_arithmetic only > for the safe cases. > E.g. one case which the posted foperator_mult handles pessimistically is > [0.0, 10.0] * [INF, INF]. This should be just [INF, INF] +-NAN IMHO, > because the 0.0 * INF case will result in NAN, while > nextafter (0.0, 1.0) * INF > will be already INF and everything larger as well. > I could in frange_mult be very conservative and for the 0 * INF cases > set result_lb and result_ub to [0.0, INF] range (corresponding signs > depending on the xor of sign of ops), but that would be quite pessimistic as > well. If one has: > [0.0, 0.0] * [10.0, INF], the result should be just [0.0, 0.0] +-NAN, > because again 0.0 * INF is NAN, but 0.0 * nextafter (INF, 0.0) is already 0.0. > > Note, the is_square case doesn't suffer from all of this mess, the result > is never NAN (unless operand is NAN). > >> It'd be nice to have some testcases. For example, from what I can see, the >> original integer multiplication code came with some tests in >> gcc.dg/tree-ssa/vrp13.c (commit 9983270bec0a18). It'd be nice to have some >> sanity checks, especially because so many things can go wrong with floats. >> >> I'll leave it to you to decide what tests to include. > > I've tried following, but it suffers from various issues: > 1) we don't handle __builtin_signbit (whatever) == 0 (or != 0) as guarantee > that in the guarded code whatever has signbit 0 or 1 We have a range-op entry for __builtin_signbit in cfn_signbit. Is this a shortcoming of this code, or something else? > 2) __builtin_isinf (x) > 0 is lowered to x > DBL_MAX, but unfortunately we don't > infer from that [INF,INF] range, but [DBL_MAX, INF] range > 3) what I wrote above, I think we don't handle [0, 2] * [INF, INF] right but > due to 2) we can't see it Doesn't this boil down to a representation issue? I wonder if we should bite the bullet and tweak build_gt() and build_lt() to represent open ranges. In theory it should be one more/less ULP, while adjusting for HONOR_INFINITIES. If the signbit issue were resolved and we could represent > and < properly, would that allow us to write proper testcases without having to writing a plug-in (which I assume is a lot harder)? Aldy > > So, maybe for now a selftest will be better than a testcase, or > alternatively a plugin test which acts like a selftest. > > /* { dg-do compile { target { ! { vax-*-* powerpc-*-*spe pdp11-*-* } } } } */ > /* { dg-options "-O2 -fno-trapping-math -fno-signaling-nans -fsigned-zeros -fno-tree-fre -fno-tree-dominator-opts -fno-thread-jumps -fdump-tree-optimized" } */ > /* { dg-add-options ieee } */ > > void > foo (double x, double y) > { > const double inf = __builtin_inf (); > const double minf = -inf; > if (__builtin_isnan (x) || __builtin_isnan (y)) > return; > #define TEST(n, xl, xu, yl, yu, rl, ru, nan) \ > if ((__builtin_isinf (xl) > 0 \ > ? x > 0.0 && __builtin_isinf (x) \ > : __builtin_isinf (xu) < 0 \ > ? x < 0.0 && __builtin_isinf (x) \ > : x >= xl && x <= xu \ > && (xl != 0.0 \ > || __builtin_signbit (xl) \ > || !__builtin_signbit (x)) \ > && (xu != 0.0 \ > || !__builtin_signbit (xu) \ > || __builtin_signbit (x))) \ > && (__builtin_isinf (yl) > 0 \ > ? y > 0.0 && __builtin_isinf (y) \ > : __builtin_isinf (yu) < 0 \ > ? y < 0.0 && __builtin_isinf (y) \ > : y >= yl && y <= yu \ > && (yl != 0.0 \ > || __builtin_signbit (yl) \ > || !__builtin_signbit (y)) \ > && (yu != 0.0 \ > || !__builtin_signbit (yu) \ > || __builtin_signbit (y)))) \ > { \ > double r##n = x * y; \ > if (nan == 2) \ > { \ > if (!__builtin_isnan (r##n)) \ > __builtin_abort (); \ > } \ > else if (nan == 1) \ > { \ > if (!__builtin_isnan (r##n)) \ > { \ > if (r##n < rl || r##n > ru) \ > __builtin_abort (); \ > } \ > } \ > else \ > { \ > if (__builtin_isnan (r##n)) \ > __builtin_abort (); \ > if (r##n < rl || r##n > ru) \ > __builtin_abort (); \ > } \ > } > #define TEST2(n, xl, xu, rl, ru) \ > if (__builtin_isinf (xl) > 0 \ > ? x > 0.0 && __builtin_isinf (x) \ > : __builtin_isinf (xu) < 0 \ > ? x < 0.0 && __builtin_isinf (x) \ > : x >= xl && x <= xu \ > && (xl != 0.0 \ > || __builtin_signbit (xl) \ > || !__builtin_signbit (x)) \ > && (xu != 0.0 \ > || !__builtin_signbit (xu) \ > || __builtin_signbit (x))) \ > { \ > double s##n = x * x; \ > if (__builtin_isnan (s##n)) \ > __builtin_abort (); \ > if (s##n < rl || s##n > ru) \ > __builtin_abort (); \ > } > TEST (1, 2.0, 4.0, 6.0, 8.0, 12.0, 32.0, 0); > TEST (2, -2.0, 3.0, -7.0, 4.0, -21.0, 14.0, 0); > TEST (3, -9.0, 5.0, 8.0, 10.0, -90.0, 50.0, 0); > TEST (4, -0.0, 0.0, 16.0, 32.0, -0.0, 0.0, 0); > TEST (5, -0.0, 0.0, 16.0, 32.0, -0.0, 0.0, 0); > TEST (6, 0.0, 0.0, 16.0, 32.0, 0.0, 0.0, 0); > TEST (7, 0.0, 0.0, 16.0, 32.0, 0.0, 0.0, 0); > TEST (8, -0.0, -0.0, 16.0, 32.0, -0.0, -0.0, 0); > TEST (9, -0.0, -0.0, 16.0, 32.0, -0.0, -0.0, 0); > TEST (10, minf, inf, minf, inf, minf, inf, 1); > TEST (11, -0.0, 0.0, 128.0, inf, -0.0, 0.0, 1); > TEST (12, -0.0, 0.0, inf, inf, 0.0, 0.0, 2); > TEST (13, minf, minf, 0.0, 0.0, 0.0, 0.0, 2); > TEST (14, 0.0, 2.0, inf, inf, inf, inf, 1); > TEST (15, 0.0, 2.0, minf, minf, minf, minf, 1); > TEST (16, inf, inf, -0.0, 2.0, minf, inf, 1); > TEST (17, minf, minf, -0.0, 3.0, minf, inf, 1); > > TEST2 (1, 2.0, 4.0, 4.0, 16.0); > TEST2 (2, -0.0, 0.0, -0.0, 0.0); > TEST2 (3, 0.0, inf, 0.0, inf); > TEST2 (4, inf, inf, inf, inf); > } > > > Jakub >