From patchwork Wed Oct 20 13:00:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 46439 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D04E5385803B for ; Wed, 20 Oct 2021 13:01:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D04E5385803B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1634734884; bh=ettUoa9q+tuPg0aQmyKyTzeIHpA8pW/R3G2KlmpFG6Y=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=VwXAMedsSyQDBoYJf3X4T82mAZmYxjjolOSYlOKUJ7c0HA31PXojpfZU68JkDiaoI HgUQzLqMIUflwWNbPZyMo01FTAxhD7JrtwF/1jaak34HtkC0KAItrYN4CqW/i7DOI+ DTc8fgMslvRc0KAGsWcswkwuszQuLy+MZ6eK43pI= 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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTPS id 4A71F3858412 for ; Wed, 20 Oct 2021 13:00:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4A71F3858412 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-551-Wn95m2RZPAaij5EaDMA3pg-1; Wed, 20 Oct 2021 09:00:18 -0400 X-MC-Unique: Wn95m2RZPAaij5EaDMA3pg-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 54C911006AA3; Wed, 20 Oct 2021 13:00:16 +0000 (UTC) Received: from localhost (unknown [10.33.36.194]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A176794A3; Wed, 20 Oct 2021 13:00:14 +0000 (UTC) Date: Wed, 20 Oct 2021 14:00:14 +0100 To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH v2] libstdc++: Add support for POWER9 DARN instruction to std::random_device Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Cc: Bill Schmidt , Segher Boessenkool Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" On 20/10/21 10:12 +0100, Jonathan Wakely wrote: >On 19/10/21 17:47 +0100, Jonathan Wakely wrote: >>The ISA-3.0 instruction set includes DARN ("deliver a random number") >>which can be used similar to the existing support for RDRAND and RDSEED. >> >>libstdc++-v3/ChangeLog: >> >> * src/c++11/random.cc (USE_DARN): Define. >> (__ppc_darn): New function to use POWER9 DARN instruction. >> (Which): Add 'darn' enumerator. >> (which_source): Check for __ppc_darn. >> (random_device::_M_init): Support "darn" and "hw" tokens. >> (random_device::_M_getentropy): Add darn to switch. >> * testsuite/26_numerics/random/random_device/cons/token.cc: >> Check "darn" token. >> * testsuite/26_numerics/random/random_device/entropy.cc: >> Likewise. >> >>Tested powerpc64le-linux (power8 and power9) and x86_64-linux. >> >>The new "darn" (power-specific) and "hw" (x86 and power) >>strings should be documented, but I'll do that if this gets committed. >> >>Most of this patch is just "more of the same", similar to the existing >>code for RDRAND and RDSEED on x86, but the parts of the patch I'd like >>more eyes on are: >> >> >>+#elif defined __powerpc__ && defined __BUILTIN_CPU_SUPPORTS__ >>+# define USE_DARN 1 >>#endif > >This means DARN can only be used when __builtin_cpu_supports is >available, which means glibc 2.23 ... is that acceptable? It means >RHEL 7 wouldn't be able to use DARN, but RHEL 8 would. > >There certainly are POWER9 machines running RHEL 7 and similar >vintages (the GCC compile farm has one) so if there's another way to >check for ISA 3.0 then I could use that. > >If __POWER9_VECTOR__ is defined when building libstdc++, presumably >that means the whole library can only be run on POWER9 hardware. So >would that mean we don't need to check __builtin_cpu_supports("darn") >when __POWER9_VECTOR__ is defined? Or is it possible to build with >-mcpu=power8 -mpower9-vector and run it on h/w without the DARN >instruction? > >Also, I forgot to add a configure check that the assembler supports >darn, which is another prerequisite for using it here. > >>@@ -135,6 +137,15 @@ namespace std _GLIBCXX_VISIBILITY(default) >>#endif >>#endif >> >>+#ifdef USE_DARN >>+ unsigned int >>+ __attribute__((target("power9"))) > >Oops, that should be "cpu=power9". > >With that change it works on a POWER9 machine (9009-42A) with glibc >2.34 and binutils 2.35. > Here's the updated patch with a configure check for assembler support, and the target attribute fixed. This still requires Glibc 2.23 for __builtin_cpu_supports, which I'm assuming is acceptable. commit a6f925407dd05c593b230da1627435adc53584f8 Author: Jonathan Wakely Date: Wed Oct 20 09:25:24 2021 libstdc++: Add support for POWER9 DARN instruction to std::random_device The ISA-3.0 instruction set includes DARN ("deliver a random number") which can be used similar to the existing support for RDRAND and RDSEED. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_CHECK_PPC_DARN): Check assembler. * config.h.in: Regenerate. * configure: Regenerate. * configure.ac: Use GLIBCXX_CHECK_PPC_DARN. * src/c++11/random.cc [_GLIBCXX_PPC_DARN] (USE_DARN): Define. (__ppc_darn): New function to use POWER9 DARN instruction. (Which): Add 'darn' enumerator. (which_source): Check for __ppc_darn. (random_device::_M_init): Support "darn" and "hw" tokens. (random_device::_M_getentropy): Add darn to switch. * testsuite/26_numerics/random/random_device/cons/token.cc: Check "darn" token. * testsuite/26_numerics/random/random_device/entropy.cc: Likewise. diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 90ecc4a87a2..9ff9ceb20ac 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -4100,6 +4100,27 @@ AC_DEFUN([GLIBCXX_CHECK_X86_RDSEED], [ AC_MSG_RESULT($ac_cv_x86_rdseed) ]) +dnl +dnl Check whether darn is supported in the assembler. +AC_DEFUN([GLIBCXX_CHECK_PPC_DARN], [ + AC_MSG_CHECKING([for darn support in assembler]) + AC_CACHE_VAL(ac_cv_ppc_darn, [ + ac_cv_ppc_darn=no + case "$target" in + powerpc*-*-*) + AC_TRY_COMPILE(, [ + signed int x; + __asm__ __volatile__ (".machine power9; darn %0,0;": "=r" (x)); + ], [ac_cv_ppc_darn=yes], [ac_cv_ppc_darn=no]) + esac + ]) + if test $ac_cv_ppc_darn = yes; then + AC_DEFINE(_GLIBCXX_PPC_DARN, 1, + [ Defined if as can handle darn. ]) + fi + AC_MSG_RESULT($ac_cv_ppc_darn) +]) + dnl dnl Check whether get_nprocs is available in , and define _GLIBCXX_USE_GET_NPROCS. dnl diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index 2d68b3672b9..1189c68c380 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -467,6 +467,8 @@ GCC_CHECK_ASSEMBLER_HWCAP GLIBCXX_CHECK_X86_RDRAND # Check if assembler supports rdseed opcode. GLIBCXX_CHECK_X86_RDSEED +# Check if assembler supports darn opcode. +GLIBCXX_CHECK_PPC_DARN # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE. GLIBCXX_CONFIGURE_TESTSUITE diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc index 4b64bde00ea..213ad691837 100644 --- a/libstdc++-v3/src/c++11/random.cc +++ b/libstdc++-v3/src/c++11/random.cc @@ -37,6 +37,9 @@ # ifdef _GLIBCXX_X86_RDSEED # define USE_RDSEED 1 # endif +#elif defined __powerpc__ && defined __BUILTIN_CPU_SUPPORTS__ \ + && defined _GLIBCXX_PPC_DARN +# define USE_DARN 1 #endif #include @@ -69,7 +72,7 @@ #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM // The OS provides a source of randomness we can use. # pragma GCC poison _M_mt -#elif defined USE_RDRAND || defined USE_RDSEED +#elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN // Hardware instructions might be available, but use cpuid checks at runtime. # pragma GCC poison _M_mt // If the runtime cpuid checks fail we'll use a linear congruential engine. @@ -135,6 +138,15 @@ namespace std _GLIBCXX_VISIBILITY(default) #endif #endif +#ifdef USE_DARN + unsigned int + __attribute__((target("cpu=power9"))) + __ppc_darn(void*) + { + return __builtin_darn_32(); + } +#endif + #ifdef _GLIBCXX_USE_CRT_RAND_S unsigned int __winxp_rand_s(void*) @@ -193,11 +205,16 @@ namespace std _GLIBCXX_VISIBILITY(default) } #endif - enum Which { - rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16, + enum Which : unsigned { + device_file = 1, prng = 2, rand_s = 4, + rdseed = 64, rdrand = 128, darn = 256, any = 0xffff }; + constexpr Which + operator|(Which l, Which r) noexcept + { return Which(unsigned(l) | unsigned(r)); } + inline Which which_source(random_device::result_type (*func [[maybe_unused]])(void*), void* file [[maybe_unused]]) @@ -221,6 +238,11 @@ namespace std _GLIBCXX_VISIBILITY(default) return rdrand; #endif +#ifdef USE_DARN + if (func == &__ppc_darn) + return darn; +#endif + #ifdef _GLIBCXX_USE_DEV_RANDOM if (file != nullptr) return device_file; @@ -269,6 +291,14 @@ namespace std _GLIBCXX_VISIBILITY(default) else if (token == "rdrand" || token == "rdrnd") which = rdrand; #endif // USE_RDRAND +#ifdef USE_DARN + else if (token == "darn") + which = darn; +#endif +#if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN + else if (token == "hw" || token == "hardware") + which = rdrand | rdseed | darn; +#endif #ifdef _GLIBCXX_USE_CRT_RAND_S else if (token == "rand_s") which = rand_s; @@ -346,6 +376,17 @@ namespace std _GLIBCXX_VISIBILITY(default) } #endif // USE_RDRAND +#ifdef USE_DARN + if (which & darn) + { + if (__builtin_cpu_supports("darn")) + { + _M_func = &__ppc_darn; + return; + } + } +#endif // USE_DARN + #ifdef _GLIBCXX_USE_DEV_RANDOM if (which & device_file) { @@ -497,6 +538,7 @@ namespace std _GLIBCXX_VISIBILITY(default) { case rdrand: case rdseed: + case darn: return (double) max; case rand_s: case prng: diff --git a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc index aeb7403e830..d6ac3a37c64 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc @@ -51,8 +51,9 @@ test03() { // At least one of these tokens should be valid. const std::string tokens[] = { - "rdseed", "rdrand", "rand_s", "/dev/urandom", "/dev/random", "mt19937", - "prng" + "rdseed", "rdrand", "darn", + "rand_s", "/dev/urandom", "/dev/random", + "mt19937", "prng" }; int count = 0; for (const std::string& token : tokens) diff --git a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc index 9ef1538d2bb..6f3ebb1b38e 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc @@ -22,7 +22,7 @@ test01() VERIFY( entropy <= max ); } - for (auto token : { "rdrand", "rdseed" }) + for (auto token : { "rdrand", "rdseed", "darn", "hw" }) if (__gnu_test::random_device_available(token)) { const double entropy = std::random_device(token).entropy();