From: Jonathan Wakely <jwakely@redhat.com>
To: Stephan Bergmann <sbergman@redhat.com>
Cc: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
Date: Wed, 4 Nov 2020 10:38:27 +0000 [thread overview]
Message-ID: <20201104103827.GB503596@redhat.com> (raw)
In-Reply-To: <20201104101503.GA503596@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 11704 bytes --]
On 04/11/20 10:15 +0000, Jonathan Wakely wrote:
>On 04/11/20 09:45 +0100, Stephan Bergmann via Libstdc++ wrote:
>>On 03/11/2020 23:25, Jonathan Wakely wrote:
>>>On 03/11/20 22:28 +0100, Stephan Bergmann via Libstdc++ wrote:
>>>>On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
>>>>>This extends the fast path to also work when the URBG's range of
>>>>>possible values is not the entire range of its result_type. Previously,
>>>>>the slow path would be used for engines with a uint_fast32_t result type
>>>>>if that type is actually a typedef for uint64_t rather than uint32_t.
>>>>>After this change, the generator's result_type is not important, only
>>>>>the range of possible value that generator can produce. If the
>>>>>generator's range is exactly UINT64_MAX then the calculation will be
>>>>>done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
>>>>>it will be done using 64-bit and 32-bit integers.
>>>>>
>>>>>In practice, this benefits most of the engines and engine adaptors
>>>>>defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
>>>>>is because std::minstd_rand0 and std::mt19937 and others use
>>>>>uint_fast32_t, which is a typedef for uint64_t.
>>>>>
>>>>>The code now makes use of the recently-clarified requirement that the
>>>>>generator's min() and max() functions are usable in constant
>>>>>expressions (see LWG 2154).
>>>>>
>>>>>libstdc++-v3/ChangeLog:
>>>>>
>>>>>Â Â Â Â * include/bits/uniform_int_dist.h (_Power_of_two): Add
>>>>>Â Â Â Â constexpr.
>>>>>Â Â Â Â (uniform_int_distribution::_S_nd): Add static_assert to ensure
>>>>>Â Â Â Â the wider type is twice as wide as the result type.
>>>>>Â Â Â Â (uniform_int_distribution::__generate_impl): Add static_assert
>>>>>Â Â Â Â and declare variables as constexpr where appropriate.
>>>>>Â Â Â Â (uniform_int_distribution:operator()): Likewise. Only consider
>>>>>Â Â Â Â the uniform random bit generator's range of possible results
>>>>>Â Â Â Â when deciding whether _S_nd can be used, not the __uctype type.
>>>>>
>>>>>Tested x86_64-linux. Committed to trunk.
>>>>
>>>>At least with recent Clang trunk, this causes e.g.
>>>>
>>>>>$ cat test.cc
>>>>>#include <random>
>>>>>void f(std::default_random_engine e) {
>>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>>
>>>>to fail with
>>>>
>>>>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17
>>>>>-fsyntax-only test.cc
>>>>>In file included from test.cc:1:
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40:
>>>>>
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52:
>>>>>
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66:
>>>>>
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17:
>>>>>error: static_assert expression is not an integral constant
>>>>>expression
>>>>>Â Â Â Â Â Â static_assert( __urng.min() < __urng.max(),
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24:
>>>>>note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned
>>>>>long, 16807, 0, 2147483647>>' requested here
>>>>>Â Â Â Â Â Â { return this->operator()(__urng, _M_param); }
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>test.cc:2:80: note: in instantiation of function template
>>>>>specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned
>>>>>long, 16807, 0, 2147483647>>' requested here
>>>>>void f(std::default_random_engine e) {
>>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>>>^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17:
>>>>>note: function parameter '__urng' with unknown value cannot be
>>>>>used in a constant expression
>>>>>Â Â Â Â Â Â static_assert( __urng.min() < __urng.max(),
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â operator()(_UniformRandomBitGenerator& __urng,
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21:
>>>>>error: constexpr variable '__urngmin' must be initialized by a
>>>>>constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngmin = __urng.min();
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^Â Â Â Â Â Â Â Â Â Â ~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33:
>>>>>note: function parameter '__urng' with unknown value cannot be
>>>>>used in a constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngmin = __urng.min();
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â operator()(_UniformRandomBitGenerator& __urng,
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21:
>>>>>error: constexpr variable '__urngmax' must be initialized by a
>>>>>constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngmax = __urng.max();
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^Â Â Â Â Â Â Â Â Â Â ~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33:
>>>>>note: function parameter '__urng' with unknown value cannot be
>>>>>used in a constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngmax = __urng.max();
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â operator()(_UniformRandomBitGenerator& __urng,
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21:
>>>>>error: constexpr variable '__urngrange' must be initialized by
>>>>>a constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^Â Â Â Â Â Â Â Â Â Â Â Â ~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35:
>>>>>note: initializer of '__urngmax' is not a constant expression
>>>>>Â Â Â Â Â Â constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â constexpr __uctype __urngmax = __urng.max();
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31:
>>>>>error: constexpr if condition is not a constant expression
>>>>>Â Â Â Â Â Â Â Â Â Â if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31:
>>>>>note: initializer of '__urngrange' is not a constant
>>>>>expression
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31:
>>>>>error: constexpr if condition is not a constant expression
>>>>>Â Â Â Â Â Â Â Â Â Â if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31:
>>>>>note: initializer of '__urngrange' is not a constant
>>>>>expression
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21:
>>>>>note: declared here
>>>>>Â Â Â Â Â Â constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^
>>>>>6 errors generated.
>>>>
>>>>which would be fixed by something like
>>>>
>>>>>diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>index 524593bb984..d9c7ea96fda 100644
>>>>>--- a/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>@@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>>Â Â Â Â Â Â typedef typename make_unsigned<result_type>::type __utype;
>>>>>Â Â Â Â Â Â typedef typename common_type<_Gresult_type,
>>>>>__utype>::type __uctype;
>>>>>-Â Â Â Â Â Â static_assert( __urng.min() < __urng.max(),
>>>>>+Â Â Â Â Â Â static_assert( _UniformRandomBitGenerator::min() <
>>>>>_UniformRandomBitGenerator::max(),
>>>>>Â Â Â Â Â Â Â Â Â Â "Uniform random bit generator must define min() < max()");
>>>>>-Â Â Â Â Â Â constexpr __uctype __urngmin = __urng.min();
>>>>>-Â Â Â Â Â Â constexpr __uctype __urngmax = __urng.max();
>>>>>+Â Â Â Â Â Â constexpr __uctype __urngmin =
>>>>>_UniformRandomBitGenerator::min();
>>>>>+Â Â Â Â Â Â constexpr __uctype __urngmax =
>>>>>_UniformRandomBitGenerator::max();
>>>>>Â Â Â Â Â Â constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>Â Â Â Â Â Â const __uctype __urange
>>>>>Â Â Â Â Â Â Â Â = __uctype(__param.b()) - __uctype(__param.a());
>>>>
>>>>(and I think there are further similar issues in this change).
>>>
>>>I think this is a Clang bug, but I'll change the code anyway.
>>
>>To me it looks like it boils down to disagreement between g++ and
>>clang++ over
>>
>>>struct S { static constexpr int f() { return 0; } };
>>>void f(S & s) { static_assert(s.f(), ""); }
>>
>>where I think Clang might be right in rejecting it based on
>>[expr.const] "An expression e is a core constant expression unless
>>[...] an id-expression that refers to a variable or data member of
>>reference type unless the reference has a preceding initialization
>>[...]"
>
>GCC, Intel icc and MSVC all accept it:
>
> https://godbolt.org/z/hTsT96
But EDG rejects it without the --g++ option (which is the mode icc
uses on GNU/Linux, I believe).
I've pushed a slightly different fix (I didn't see your patch at the
bottom of the first email until after I'd already done this version).
Tested powerpc64le-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1686 bytes --]
commit 24366207b77481bceebb425569932297c441e04e
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Nov 4 10:36:45 2020
libstdc++: Fix constant expressions in std::uniform_int_distribution
Clang and EDG say the class member access expressions __urng.min() and
__urng.max() are not constant expressions, because the object expression
__urng is not usable in a constant expresion. Use a qualified-id to call
those static member functions instead.
Co-authored-by: Stephan Bergmann <sbergman@redhat.com>
libstdc++-v3/ChangeLog:
* include/bits/uniform_int_dist.h (uniform_int_distribution::_S_nd):
Use qualified-id to refer to static member functions.
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 524593bb9847..8f02b85c9bb0 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -278,12 +278,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef typename make_unsigned<result_type>::type __utype;
typedef typename common_type<_Gresult_type, __utype>::type __uctype;
- static_assert( __urng.min() < __urng.max(),
+ constexpr __uctype __urngmin = _UniformRandomBitGenerator::min();
+ constexpr __uctype __urngmax = _UniformRandomBitGenerator::max();
+ static_assert( __urngmin < __urngmax,
"Uniform random bit generator must define min() < max()");
-
- constexpr __uctype __urngmin = __urng.min();
- constexpr __uctype __urngmax = __urng.max();
constexpr __uctype __urngrange = __urngmax - __urngmin;
+
const __uctype __urange
= __uctype(__param.b()) - __uctype(__param.a());
prev parent reply other threads:[~2020-11-04 10:38 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-29 14:59 Jonathan Wakely
2020-11-03 21:28 ` Stephan Bergmann
2020-11-03 22:25 ` Jonathan Wakely
2020-11-04 8:45 ` Stephan Bergmann
2020-11-04 8:52 ` Ville Voutilainen
2020-11-04 10:15 ` Jonathan Wakely
2020-11-04 10:38 ` Jonathan Wakely [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201104103827.GB503596@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
--cc=sbergman@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).