From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lxmtout2.gsi.de (lxmtout2.gsi.de [140.181.3.112]) by sourceware.org (Postfix) with ESMTPS id AD2FE3851C21; Wed, 16 Dec 2020 11:58:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org AD2FE3851C21 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gsi.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=M.Kretz@gsi.de Received: from localhost (localhost [127.0.0.1]) by lxmtout2.gsi.de (Postfix) with ESMTP id 4F0AD202AD64; Wed, 16 Dec 2020 12:58:35 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at lxmtout2.gsi.de Received: from lxmtout2.gsi.de ([127.0.0.1]) by localhost (lxmtout2.gsi.de [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 3FnLIL4MzoWz; Wed, 16 Dec 2020 12:58:35 +0100 (CET) Received: from srvex3.campus.gsi.de (srvex3.campus.gsi.de [10.10.4.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by lxmtout2.gsi.de (Postfix) with ESMTPS id 25646202AD5D; Wed, 16 Dec 2020 12:58:34 +0100 (CET) Received: from excalibur.localnet (140.181.3.12) by srvex3.campus.gsi.de (10.10.4.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2106.2; Wed, 16 Dec 2020 12:58:33 +0100 From: Matthias Kretz To: , Subject: [PATCH] Add simd testsuite Date: Wed, 16 Dec 2020 12:58:32 +0100 Message-ID: <8364569.lWL0Ik8vYZ@excalibur> Organization: GSI Helmholtzzentrum =?UTF-8?B?ZsO8cg==?= Schwerionenforschung MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart3116913.eMUbO1HJkO" Content-Transfer-Encoding: 7Bit X-Originating-IP: [140.181.3.12] X-ClientProxiedBy: SRVEX2.campus.gsi.de (10.10.4.15) To srvex3.campus.gsi.de (10.10.4.16) X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, BODY_8BITS, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SCC_5_SHORT_WORD_LINES, SPF_PASS, TXREP, T_SPF_HELO_PERMERROR autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Dec 2020 11:58:54 -0000 --nextPart3116913.eMUbO1HJkO Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" This is the second patch for std::experimental::simd, adding the testsuite.= As=20 discussed with Jonathan, the simd testsuite comes via its own check-simd=20 target. The testsuite is so large that even marking all tests as "expensive= ",=20 it still increased make check -j8 (with 8 cores) by more than 4 minutes (on= ly=20 to determine to compile and run nothing). =46rom: Matthias Kretz The new check-simd target creates a subdirectory, generates the necessary Makefiles, and spawns submakes to build and run the tests. libstdc++-v3/ChangeLog: * scripts/check_simd: New file. This script is called from the the check-simd target. It determines a set of compiler flags and simulator setups for calling generate_makefile.sh and passes the information back to the check-simd target, which recurses to the generated Makefiles. * scripts/create_testsuite_files: Remove files below simd/tests/ from testsuite_files and place them in testsuite_files_simd. * testsuite/Makefile.am: Add testsuite_files_simd. Add check-simd target. * testsuite/experimental/simd/driver.sh: New file. This script compiles and runs a given simd test, logging its output and status. It uses the timeout command to implement compile and test timeouts. * testsuite/experimental/simd/generate_makefile.sh: New file. This script generates a Makefile which uses driver.sh to compile and run the tests and collect the logs into a single log file. * testsuite/experimental/simd/tests/abs.cc: New file. Tests abs(simd). * testsuite/experimental/simd/tests/algorithms.cc: New file. Tests min/max(simd, simd). * testsuite/experimental/simd/tests/bits/conversions.h: New file. Contains functions to support tests involving conversions. * testsuite/experimental/simd/tests/bits/make_vec.h: New file. Support functions make_mask and make_vec. * testsuite/experimental/simd/tests/bits/mathreference.h: New file. Support functions to supply precomputed math function reference data. * testsuite/experimental/simd/tests/bits/metahelpers.h: New file. Support code for SFINAE testing. * testsuite/experimental/simd/tests/bits/simd_view.h: New file. * testsuite/experimental/simd/tests/bits/test_values.h: New file. Test functions to easily drive a test with simd objects initialized from a given list of values and a range of random values. * testsuite/experimental/simd/tests/bits/ulp.h: New file. Support code to determine the ULP distance of simd objects. * testsuite/experimental/simd/tests/bits/verify.h: New file. Test framework for COMPARE'ing simd objects and instantiating the test templates with value_type and ABI tag. * testsuite/experimental/simd/tests/broadcast.cc: New file. Test simd broadcasts. * testsuite/experimental/simd/tests/casts.cc: New file. Test simd casts. * testsuite/experimental/simd/tests/fpclassify.cc: New file. Test floating-point classification functions. * testsuite/experimental/simd/tests/frexp.cc: New file. Test frexp(simd). * testsuite/experimental/simd/tests/generator.cc: New file. Test simd generator constructor. * testsuite/experimental/simd/tests/hypot3_fma.cc: New file. Test 3-arg hypot(simd,simd,simd) and fma(simd,simd,sim). * testsuite/experimental/simd/tests/integer_operators.cc: New file. Test integer operators. * testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc: New file. Test ldexp(simd), scalbn(simd), scalbln(simd), and modf(simd). * testsuite/experimental/simd/tests/loadstore.cc: New file. Test (converting) simd loads and stores. * testsuite/experimental/simd/tests/logarithm.cc: New file. Test log*(simd). * testsuite/experimental/simd/tests/mask_broadcast.cc: New file. Test simd_mask broadcasts. * testsuite/experimental/simd/tests/mask_conversions.cc: New file. Test simd_mask conversions. * testsuite/experimental/simd/tests/mask_implicit_cvt.cc: New file. Test simd_mask implicit conversions. * testsuite/experimental/simd/tests/mask_loadstore.cc: New file. Test simd_mask loads and stores. * testsuite/experimental/simd/tests/mask_operator_cvt.cc: New file. Test simd_mask operators convert as specified. * testsuite/experimental/simd/tests/mask_operators.cc: New file. Test simd_mask compares, subscripts, and negation. * testsuite/experimental/simd/tests/mask_reductions.cc: New file. Test simd_mask reductions. * testsuite/experimental/simd/tests/math_1arg.cc: New file. Test 1-arg math functions on simd. * testsuite/experimental/simd/tests/math_2arg.cc: New file. Test 2-arg math functions on simd. * testsuite/experimental/simd/tests/operator_cvt.cc: New file. Test implicit conversions on simd binary operators behave as specified. * testsuite/experimental/simd/tests/operators.cc: New file. Test simd compares, subscripts, not, unary minus, plus, minus, multiplies, divides, increment, and decrement. * testsuite/experimental/simd/tests/reductions.cc: New file. Test reduce(simd). * testsuite/experimental/simd/tests/remqo.cc: New file. Test remqo(simd). * testsuite/experimental/simd/tests/simd.cc: New file. Basic sanity checks of simd types. * testsuite/experimental/simd/tests/sincos.cc: New file. Test sin(simd) and cos(simd). * testsuite/experimental/simd/tests/split_concat.cc: New file. Test split(simd) and concat(simd, simd). * testsuite/experimental/simd/tests/splits.cc: New file. Test split(simd_mask). * testsuite/experimental/simd/tests/trigonometric.cc: New file. Test remaining trigonometric functions on simd. * testsuite/experimental/simd/tests/trunc_ceil_floor.cc: New file. Test trunc(simd), ceil(simd), and floor(simd). * testsuite/experimental/simd/tests/where.cc: New file. Test masked operations using where. =2D-- libstdc++-v3/scripts/check_simd | 76 ++ libstdc++-v3/scripts/create_testsuite_files | 6 +- libstdc++-v3/testsuite/Makefile.am | 17 +- .../testsuite/experimental/simd/driver.sh | 249 ++++ .../experimental/simd/generate_makefile.sh | 250 ++++ .../testsuite/experimental/simd/tests/abs.cc | 24 + .../experimental/simd/tests/algorithms.cc | 13 + .../simd/tests/bits/conversions.h | 167 +++ .../experimental/simd/tests/bits/make_vec.h | 69 ++ .../simd/tests/bits/mathreference.h | 143 +++ .../simd/tests/bits/metahelpers.h | 147 +++ .../experimental/simd/tests/bits/simd_view.h | 131 ++ .../simd/tests/bits/test_values.h | 366 ++++++ .../experimental/simd/tests/bits/ulp.h | 111 ++ .../experimental/simd/tests/bits/verify.h | 336 ++++++ .../experimental/simd/tests/broadcast.cc | 87 ++ .../experimental/simd/tests/casts.cc | 152 +++ .../experimental/simd/tests/fpclassify.cc | 89 ++ .../experimental/simd/tests/frexp.cc | 68 ++ .../experimental/simd/tests/generator.cc | 41 + .../experimental/simd/tests/hypot3_fma.cc | 134 +++ .../simd/tests/integer_operators.cc | 218 ++++ .../simd/tests/ldexp_scalbn_scalbln_modf.cc | 152 +++ .../experimental/simd/tests/loadstore.cc | 212 ++++ .../experimental/simd/tests/logarithm.cc | 66 ++ .../experimental/simd/tests/mask_broadcast.cc | 50 + .../simd/tests/mask_conversions.cc | 96 ++ .../simd/tests/mask_implicit_cvt.cc | 85 ++ .../experimental/simd/tests/mask_loadstore.cc | 144 +++ .../simd/tests/mask_operator_cvt.cc | 94 ++ .../experimental/simd/tests/mask_operators.cc | 40 + .../simd/tests/mask_reductions.cc | 209 ++++ .../experimental/simd/tests/math_1arg.cc | 90 ++ .../experimental/simd/tests/math_2arg.cc | 62 + .../experimental/simd/tests/operator_cvt.cc | 1055 +++++++++++++++++ .../experimental/simd/tests/operators.cc | 297 +++++ .../experimental/simd/tests/reductions.cc | 80 ++ .../experimental/simd/tests/remqo.cc | 53 + .../testsuite/experimental/simd/tests/simd.cc | 29 + .../experimental/simd/tests/sincos.cc | 29 + .../experimental/simd/tests/split_concat.cc | 166 +++ .../experimental/simd/tests/splits.cc | 21 + .../experimental/simd/tests/trigonometric.cc | 24 + .../simd/tests/trunc_ceil_floor.cc | 92 ++ .../experimental/simd/tests/where.cc | 119 ++ 45 files changed, 6156 insertions(+), 3 deletions(-) create mode 100755 libstdc++-v3/scripts/check_simd create mode 100755 libstdc++-v3/testsuite/experimental/simd/driver.sh create mode 100755 libstdc++-v3/testsuite/experimental/simd/ generate_makefile.sh create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/abs.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ algorithms.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ conversions.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ make_vec.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ mathreference.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ metahelpers.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ simd_view.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ test_values.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp= =2Eh create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ verify.h create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ broadcast.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/casts.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ fpclassify.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ generator.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ hypot3_fma.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ integer_operators.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ ldexp_scalbn_scalbln_modf.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ loadstore.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ logarithm.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_broadcast.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_conversions.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_implicit_cvt.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_loadstore.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_operator_cvt.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_operators.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ mask_reductions.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ math_1arg.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ math_2arg.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ operator_cvt.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ operators.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ reductions.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/simd.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ split_concat.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/splits.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ trigonometric.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/ trunc_ceil_floor.cc create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/where.cc =2D- =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Dr. Matthias Kretz https://mattkretz.github.io GSI Helmholtz Centre for Heavy Ion Research https://gsi.de std::experimental::simd https://github.com/VcDevel/std-simd =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 --nextPart3116913.eMUbO1HJkO Content-Disposition: inline; filename="0001-Add-simd-testsuite.patch" Content-Transfer-Encoding: quoted-printable Content-Type: text/x-patch; charset="utf-8"; name="0001-Add-simd-testsuite.patch" diff --git a/libstdc++-v3/scripts/check_simd b/libstdc++-v3/scripts/check_s= imd new file mode 100755 index 00000000000..2b7a17a64c9 =2D-- /dev/null +++ b/libstdc++-v3/scripts/check_simd @@ -0,0 +1,76 @@ +#!/bin/sh + +# check_simd +# Read config from $CHECK_SIMD_CONFIG file or $target_list + +scriptdir=3D"$(cd "${0%/*}" && pwd)" +srcdir=3D"$1" +builddir=3D"$2" +shift 2 +testdir=3D"$builddir/testsuite" + +CXX=3D"$("$builddir/scripts/testsuite_flags" --build-cxx)" +CXXFLAGS=3D"$("$builddir/scripts/testsuite_flags" --cxxflags) $1 -Wno-psab= i" +shift +INCLUDES=3D"$("$builddir/scripts/testsuite_flags" --build-includes)" + +target_triplet=3D$($CXX -dumpmachine) + +define_target() { + name=3D"$1" + flags=3D"$2" + sim=3D"$3" + eval "$name=3D\"flags=3D\\\"$flags\\\" +sim=3D\\\"$sim\\\"\"" +} + +if [ -f "$CHECK_SIMD_CONFIG" ]; then + . "$CHECK_SIMD_CONFIG" +elif [ -z "$CHECK_SIMD_CONFIG"]; then + if [ -z "$target_list" ]; then + target_list=3D"unix" + case "$target_triplet" in + x86_64-*) target_list=3D"unix/-march=3Dnative" ;; + i?86-*) target_list=3D"unix/-march=3Dnative" ;; + powerpc64le-*) target_list=3D"unix/-mcpu=3Dpower8" ;; + aarch64-*) target_list=3D"unix/-mcpu=3Dcortex-a53" ;; + arm-*) target_list=3D"unix/-mcpu=3Dcortex-a7" ;; + esac + fi +else + echo "Error: File not found: \$CHECK_SIMD_CONFIG=3D'$CHECK_SIMD_CONFIG'"= 1>&2 + exit 1 +fi + +# define unix with no flags and no simulator: +define_target unix + +list=3D"$target_list" + +# expand a{b,c} to a/b a/c +while [ "${list#*\{}" !=3D "${list}" ]; do + list=3D"$(echo "$list" | \ + sed -e 's#\([^ ]\+\){\([^{},]*\),\([^{}]*\)}\(/[^ ]*\)\?#\1/\2\4 \1{\3= }\4#g' \ + -e 's#{\([^{},]*\)}#/\1#g' \ + -e 's#/ # #g' -e 's#/$##')" +done + +# per a/b/c block extract flags and simulator, then make check-simd +while [ ${#list} -gt 0 ]; do + a=3D"${list%% *}" + if [ "$a" =3D "$list" ]; then + list=3D"" + else + list=3D"${list#${a} }" + fi + b=3D"${a%%/*}" + eval "eval \"\$$b\"" + flags=3D"${flags}$(echo "${a#${b}}"|sed 's#/# #g')" + subdir=3D"simd/$(echo "$flags" | sed 's#[=3D /-]##g')" + rm -f "${subdir}/Makefile" + $srcdir/testsuite/experimental/simd/generate_makefile.sh \ + --destination=3D"$testdir/$subdir" $CXX $INCLUDES $CXXFLAGS -static + echo "$subdir +$flags +$sim" +done diff --git a/libstdc++-v3/scripts/create_testsuite_files b/libstdc++-v3/scr= ipts/create_testsuite_files index 52bbb5cda5a..174c24ec05a 100755 =2D-- a/libstdc++-v3/scripts/create_testsuite_files +++ b/libstdc++-v3/scripts/create_testsuite_files @@ -27,6 +27,7 @@ tmp=3D"${TMPDIR:-/tmp}/ctt$$" tests_file_normal=3D"$outdir/testsuite_files" tests_file_inter=3D"$outdir/testsuite_files_interactive" tests_file_perf=3D"$outdir/testsuite_files_performance" +tests_file_simd=3D"$outdir/testsuite_files_simd" =20 cd $srcdir # This is the ugly version of "everything but the current directory". It's @@ -49,8 +50,11 @@ grep -v _xin $tmp.1 > $tmp.4 grep performance $tmp.4 > $tests_file_perf grep -v performance $tmp.4 > $tmp.5 =20 +grep simd/tests/ $tmp.5 > $tests_file_simd +grep -v simd/tests/ $tmp.5 > $tmp.6 + # ...more filters go here. =2Dcp $tmp.5 $tests_file_normal +cp $tmp.6 $tests_file_normal =20 rm $tmp* exit 0 diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Ma= kefile.am index 7b412411bfe..d2e282b62b9 100644 =2D-- a/libstdc++-v3/testsuite/Makefile.am +++ b/libstdc++-v3/testsuite/Makefile.am @@ -31,7 +31,8 @@ include $(top_srcdir)/fragment.am lists_of_files =3D \ testsuite_files \ testsuite_files_interactive \ =2D testsuite_files_performance + testsuite_files_performance \ + testsuite_files_simd =20 # This rule generates all of the testsuite_files* lists at once. ${lists_of_files}: @@ -185,6 +186,18 @@ check-performance: testsuite_files_performance ${perfo= rmance_script} CXXFLAGS=3D'$(CXXFLAGS)'; export CXXFLAGS; \ ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir}) =20 +# Runs the simd tests. +check-simd: $(srcdir)/experimental/simd/generate_makefile.sh \ + ${glibcxx_srcdir}/scripts/check_simd \ + testsuite_files_simd \ + ${glibcxx_builddir}/scripts/testsuite_flags + ${glibcxx_srcdir}/scripts/check_simd "${glibcxx_srcdir}" "${glibcxx_build= dir}" "$(CXXFLAGS)" | \ + while read subdir && read flags && read sim; do \ + $(MAKE) -C "$${subdir}" TESTFLAGS=3D"$${flags}" GCC_TEST_SIMULATOR=3D= "$${sim}"; \ + tail -n6 $${subdir}/simd_testsuite.sum >> .simd.summary; \ + done; \ + cat .simd.summary && rm .simd.summary + # Runs the testsuite in debug mode. debug_flags =3D "unix/-D_GLIBCXX_DEBUG" =20 @@ -234,4 +247,4 @@ CLEANFILES =3D *.txt *.tst *.exe core* filebuf_* tmp* o= stream_* *.log *.sum \ =20 # To remove directories. clean-local: =2D rm -rf de fr debug parallel binaries normal* + rm -rf de fr debug parallel binaries normal* simd diff --git a/libstdc++-v3/testsuite/experimental/simd/driver.sh b/libstdc++= =2Dv3/testsuite/experimental/simd/driver.sh new file mode 100755 index 00000000000..aabef316f47 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/driver.sh @@ -0,0 +1,249 @@ +#!/bin/sh + +type=3Dfloat +abi=3D0 +name=3D +srcdir=3D"$(cd "${0%/*}" && pwd)/tests" +sim=3D"$GCC_TEST_SIMULATOR" +quiet=3Dfalse +verbose=3Dfalse +timeout=3D180 +run_expensive=3Dfalse +if [ -n "$GCC_TEST_RUN_EXPENSIVE" ]; then + run_expensive=3Dtrue +fi +keep_failed=3Dfalse +only=3D + +usage() { + cat < + +Options: + -h, --help Print this message and exit. + -q, --quiet Only print failures. + -v, --verbose Print compiler and test output on failure. + -t , --type + The value_type to test (default: $type). + -a [0-9], --abi [0-9] + The ABI tag subset to test (default: $abi). + -n , --name + The name of the test (required). + -k, --keep-failed Keep executables of failed tests. + --srcdir The source directory of the tests (default: $srcdir). + --sim Path to an executable that is prepended to the test + execution binary (default: the value of + GCC_TEST_SIMULATOR). + --timeout-factor + Multiply the default timeout with x. + --run-expensive Compile and run tests marked as expensive (default: + true if GCC_TEST_RUN_EXPENSIVE is set, false otherwi= se). + --only Compile and run only tests matching the given patter= n. +EOF +} + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + usage + exit + ;; + -q|--quiet) + quiet=3Dtrue + ;; + -v|--verbose) + verbose=3Dtrue + ;; + --run-expensive) + run_expensive=3Dtrue + ;; + -k|--keep-failed) + keep_failed=3Dtrue + ;; + --only) + only=3D"$2" + shift + ;; + --only=3D*) + only=3D"${1#--only=3D}" + ;; + -t|--type) + type=3D"$2" + shift + ;; + --type=3D*) + type=3D"${1#--type=3D}" + ;; + -a|--abi) + abi=3D"$2" + shift + ;; + --abi=3D*) + abi=3D"${1#--abi=3D}" + ;; + -n|--name) + name=3D"$2" + shift + ;; + --name=3D*) + name=3D"${1#--name=3D}" + ;; + --srcdir) + srcdir=3D"$2" + shift + ;; + --srcdir=3D*) + srcdir=3D"${1#--srcdir=3D}" + ;; + --sim) + sim=3D"$2" + shift + ;; + --sim=3D*) + sim=3D"${1#--sim=3D}" + ;; + --timeout-factor) + timeout=3D$(awk "BEGIN { print int($timeout * $2) }") + shift + ;; + --timeout-factor=3D*) + x=3D${1#--timeout-factor=3D} + timeout=3D$(awk "BEGIN { print int($timeout * $x) }") + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +CXX=3D"$1" +shift +CXXFLAGS=3D"$@" +src=3D"${srcdir}/${name}.cc" +shorttype=3D$(echo $type|sed -e 's/long /l/' -e 's/unsigned /u/' -e 's/sig= ned /s/') +testname=3D"${name}-${shorttype}-${abi}" +exe=3D"${testname}.exe" +log=3D"${testname}.log" +sum=3D"${testname}.sum" +if [ -n "$only" ]; then + if echo "$testname"|awk "{ exit /$only/ }"; then + touch "$log" "$sum" + exit 0 + fi +fi + +if [ $abi -eq 0 ]; then + abi=3D"" +elif [ $abi -gt 0 -a $abi -lt 10 ]; then + abi=3D"-DEXTENDEDTESTS=3D$((abi-1))" +else + echo "Error: The -a argument must be a value between 0 and 9 (inclusive)= =2E" >&2 + exit 1 +fi + +fail() { + echo "FAIL: $src $type $abi ($*)" | tee -a "$sum" "$log" +} + +pass() { + $quiet || echo "PASS: $src $type $abi ($*)" + echo "PASS: $src $type $abi ($*)" >> "$sum" + echo "PASS: $src $type $abi ($*)" >> "$log" +} + +unsupported() { + $quiet || echo "UNSUPPORTED: $src $type $abi ($*)" + echo "UNSUPPORTED: $src $type $abi ($*)" >> "$sum" + echo "UNSUPPORTED: $src $type $abi ($*)" >> "$log" +} + +verify_compilation() { + failed=3D$1 + if [ $failed -eq 0 ]; then + warnings=3D$(grep -ic 'warning:' "$log") + if [ $warnings -gt 0 ]; then + fail "excess warnings:" $warnings + if $verbose; then + cat "$log" + elif ! $quiet; then + grep -i 'warning:' "$log" | head -n5 + fi + else + pass "test for excess errors" + fi + else + if [ $failed -eq 124 ]; then + fail "timeout: test for excess errors" + else + errors=3D$(grep -ic 'error:' "$log") + fail "excess errors:" $errors + fi + if $verbose; then + cat "$log" + elif ! $quiet; then + grep -i 'error:' "$log" | head -n5 + fi + exit 0 + fi +} + +verify_test() { + failed=3D$1 + if [ $failed -eq 0 ]; then + rm "$exe" + pass "execution test" + else + $keep_failed || rm "$exe" + if [ $failed -eq 124 ]; then + fail "timeout: execution test" + else + fail "execution test" + fi + if $verbose; then + if [ $(cat "$log"|wc -l) -gt 1000 ]; then + echo "[...]" + tail -n1000 "$log" + else + cat "$log" + fi + elif ! $quiet; then + grep -i fail "$log" | head -n5 + fi + exit 0 + fi +} + +write_log_and_verbose() { + echo "$*" >> "$log" + if $verbose; then + echo "$*" + fi +} + +rm -f "$log" "$sum" +touch "$log" "$sum" + +if ! $run_expensive && [ -n "$abi" ]; then + unsupported "skip expensive tests" + exit 0 +fi + +write_log_and_verbose "$CXX $src $@ -D_GLIBCXX_SIMD_TESTTYPE=3D$type $abi = =2Do $exe" +timeout $timeout "$CXX" "$src" "$@" "-D_GLIBCXX_SIMD_TESTTYPE=3D$type" $ab= i -o "$exe" >> "$log" 2>&1 +verify_compilation $? +if [ -n "$sim" ]; then + write_log_and_verbose "$sim ./$exe" + timeout $timeout $sim "./$exe" >> "$log" 2>&1 <&- +else + write_log_and_verbose "./$exe" + timeout=3D$(awk "BEGIN { print int($timeout / 2) }") + timeout $timeout "./$exe" >> "$log" 2>&1 <&- +fi +verify_test $? + +# vim: sw=3D2 et cc=3D81 si diff --git a/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh = b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh new file mode 100755 index 00000000000..a8caa4bcd4e =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh @@ -0,0 +1,250 @@ +#!/bin/sh + +srcdir=3D"$(cd "${0%/*}" && pwd)" +driver=3D"$srcdir/driver.sh" +srcdir=3D"$srcdir/tests" +sim=3D +rm_logs=3Dtrue +dst=3D. + +usage() { + cat < + +Options: + -h, --help Print this message and exit. + --srcdir The source directory of the tests (default: $srcdir). + --sim Path to an executable that is prepended to the test + execution binary (default: none). + --keep-intermediate-logs + Keep intermediate logs. + -d , --destination + Destination for the generated Makefile. If the direc= tory + does not exist it is created (default: $dst). +EOF +} + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + usage + exit + ;; + -d|--destination) + dst=3D"$2" + shift + ;; + --destination=3D*) + dst=3D"${1#--destination=3D}" + ;; + --keep-intermediate-logs) + rm_logs=3Dfalse + ;; + --srcdir) + srcdir=3D"$2" + shift + ;; + --srcdir=3D*) + srcdir=3D"${1#--srcdir=3D}" + ;; + --sim) + sim=3D"$2" + shift + ;; + --sim=3D*) + sim=3D"${1#--sim=3D}" + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +mkdir -p "$dst" +dst=3D"$dst/Makefile" +if [ -f "$dst" ]; then + echo "Error: $dst already exists. Aborting." 1>&2 + exit 1 +fi + +CXX=3D"$1" +shift + +echo "TESTFLAGS ?=3D" > "$dst" +echo CXXFLAGS =3D "$@" "\$(TESTFLAGS)" >> "$dst" +cat >> "$dst" < \$@ + @cat \$(^:log=3Dsum) > \$(@:log=3Dsum)${rmline} + +EOF + all_tests | while read file && read name; do + echo -n "$name.log:" + all_types "$file" | while read t && read type; do + echo -n " $name-$type.log" + done + cat < \$@ + @cat \$(^:log=3Dsum) > \$(@:log=3Dsum)${rmline} + +EOF + done + all_types | while read t && read type; do + cat < \$@ + @cat \$(^:log=3Dsum) > \$(@:log=3Dsum)${rmline} + +EOF + for i in $(seq 0 9); do + cat < to pass the following options:\n"\\ + "-q, --quiet Only print failures.\n"\\ + "-v, --verbose Print compiler and test output on failure.\n"\\ + "-k, --keep-failed Keep executables of failed tests.\n"\\ + "--sim Path to an executable that is prepended to the test\= n"\\ + " execution binary (default: the value of\n"\\ + " GCC_TEST_SIMULATOR).\n"\\ + "--timeout-factor \n"\\ + " Multiply the default timeout with x.\n"\\ + "--run-expensive Compile and run tests marked as expensive (default:\= n"\\ + " true if GCC_TEST_RUN_EXPENSIVE is set, false otherwi= se).\n"\\ + "--only Compile and run only tests matching the given patter= n.\n" + @echo "use TESTFLAGS=3D to pass additional compiler flags\n" + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all" + @echo "... clean" + @echo "... help" +EOF + all_tests | while read file && read name; do + echo "\t@echo '... run-${name}'" + all_types | while read t && read type; do + echo "\t@echo '... run-${name}-${type}'" + for i in $(seq 0 9); do + echo "\t@echo '... run-${name}-${type}-$i'" + done + done + done + cat <> "$dst" + diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc b/libstd= c++-v3/testsuite/experimental/simd/tests/abs.cc new file mode 100644 index 00000000000..3f81bf03a40 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc @@ -0,0 +1,24 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include // abs & sqrt +#include // integer abs +#include "bits/test_values.h" + +template + void + test() + { + if constexpr (std::is_signed_v) + { + using std::abs; + using T =3D typename V::value_type; + test_values({std::__finite_max_v, std::__norm_min_v, + -std::__norm_min_v, std::__finite_min_v, + std::__finite_min_v / 2, T(), -T(), T(-1), T(-2)}, + {1000}, [](V input) { + const V expected( + [&](auto i) { return T(std::abs(T(input[i]))); }); + COMPARE(abs(input), expected) << "input: " << input; + }); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc b= /libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc new file mode 100644 index 00000000000..f79bb6b63d2 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc @@ -0,0 +1,13 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +template + void + test() + { + using T =3D typename V::value_type; + V a{[](auto i) -> T { return i & 1u; }}; + V b{[](auto i) -> T { return (i + 1u) & 1u; }}; + COMPARE(min(a, b), V{0}); + COMPARE(max(a, b), V{1}); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversion= s.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h new file mode 100644 index 00000000000..601b783cec6 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h @@ -0,0 +1,167 @@ +#include + +// is_conversion_undefined +/* implementation-defined + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * =C2=A74.7 p3 (integral conversions) + * If the destination type is signed, the value is unchanged if it can be + * represented in the destination type (and bit-field width); otherwise, = the + * value is implementation-defined. + * + * undefined + * =3D=3D=3D=3D=3D=3D=3D=3D=3D + * =C2=A74.9/1 (floating-point conversions) + * If the source value is neither exactly represented in the destination = type + * nor between two adjacent destination values the result is undefined. + * + * =C2=A74.10/1 (floating-integral conversions) + * floating point type can be converted to integer type. + * The behavior is undefined if the truncated value cannot be + * represented in the destination type. + * + * =C2=A74.10/2 + * integer can be converted to floating point type. + * If the value being converted is outside the range of values that can be + * represented, the behavior is undefined. + */ +template + constexpr bool + is_conversion_undefined_impl(From x, std::true_type) + { + return x > static_cast(std::__finite_max_v) + || x < static_cast(std::__finite_min_v); + } + +template + constexpr bool + is_conversion_undefined_impl(From, std::false_type) + { return false; } + +template + constexpr bool + is_conversion_undefined(From x) + { + static_assert(std::is_arithmetic::value, + "this overload is only meant for builtin arithmetic types"); + return is_conversion_undefined_impl( + x, std::integral_constant< + bool, std::is_floating_point::value + && (std::is_integral::value + || (std::is_floating_point::value + && sizeof(From) > sizeof(To)))>()); + } + +static_assert(is_conversion_undefined(float(0x100000000LL)), + "testing my expectations of is_conversion_undefined"); +static_assert(!is_conversion_undefined(0x100000000LL), + "testing my expectations of is_conversion_undefined"); + +template + inline std::experimental::simd_mask + is_conversion_undefined(const std::experimental::simd& x) + { + std::experimental::simd_mask k =3D false; + for (std::size_t i =3D 0; i < x.size(); ++i) + k[i] =3D is_conversion_undefined(x[i]); + return k; + } + +template + constexpr T + genHalfBits() + { return std::__finite_max_v >> (std::__digits_v / 2); } + +template <> + constexpr long double + genHalfBits() + { return 0; } + +template <> + constexpr double + genHalfBits() + { return 0; } + +template <> + constexpr float + genHalfBits() + { return 0; } + +template + constexpr U + avoid_ub(UU x) + { return is_conversion_undefined(U(x)) ? U(0) : U(x); } + +template + constexpr U + avoid_ub2(UU x) + { return is_conversion_undefined(x) ? U(0) : avoid_ub(x); } + +// conversion test input data +template + static const std::array cvt_input_data =3D {{ + avoid_ub(0xc0000080U), + avoid_ub(0xc0000081U), + avoid_ub(0xc0000082U), + avoid_ub(0xc0000084U), + avoid_ub(0xc0000088U), + avoid_ub(0xc0000090U), + avoid_ub(0xc00000A0U), + avoid_ub(0xc00000C0U), + avoid_ub(0xc000017fU), + avoid_ub(0xc0000180U), + avoid_ub(0x100000001LL), + avoid_ub(0x100000011LL), + avoid_ub(0x100000111LL), + avoid_ub(0x100001111LL), + avoid_ub(0x100011111LL), + avoid_ub(0x100111111LL), + avoid_ub(0x101111111LL), + avoid_ub(-0x100000001LL), + avoid_ub(-0x100000011LL), + avoid_ub(-0x100000111LL), + avoid_ub(-0x100001111LL), + avoid_ub(-0x100011111LL), + avoid_ub(-0x100111111LL), + avoid_ub(-0x101111111LL), + avoid_ub(std::__norm_min_v), + avoid_ub(std::__norm_min_v + 1), + avoid_ub(std::__finite_min_v), + avoid_ub(std::__finite_min_v + 1), + avoid_ub(-1), + avoid_ub(-10), + avoid_ub(-100), + avoid_ub(-1000), + avoid_ub(-10000), + avoid_ub(0), + avoid_ub(1), + avoid_ub(genHalfBits() - 1), + avoid_ub(genHalfBits()), + avoid_ub(genHalfBits() + 1), + avoid_ub(std::__finite_max_v - 1), + avoid_ub(std::__finite_max_v), + avoid_ub(std::__finite_max_v - 0xff), + avoid_ub(std::__finite_max_v - 0xff), + avoid_ub(std::__finite_max_v - 0x55), + avoid_ub(-(std::__finite_min_v + 1)), + avoid_ub(-std::__finite_max_v), + avoid_ub(std::__finite_max_v / std::pow(2., sizeof(T) * 6 - 1= )), + avoid_ub2(-std::__finite_max_v / std::pow(2., sizeof(T) * 6 -= 1)), + avoid_ub(std::__finite_max_v / std::pow(2., sizeof(T) * 4 - 1= )), + avoid_ub2(-std::__finite_max_v / std::pow(2., sizeof(T) * 4 -= 1)), + avoid_ub(std::__finite_max_v / std::pow(2., sizeof(T) * 2 - 1= )), + avoid_ub2(-std::__finite_max_v / std::pow(2., sizeof(T) * 2 -= 1)), + avoid_ub(std::__finite_max_v - 1), + avoid_ub(std::__finite_max_v * 0.75), + }}; + +template + struct cvt_inputs + { + static constexpr size_t + size() + { return cvt_input_data.size(); } + + U + operator[](size_t i) const + { return cvt_input_data[i]; } + }; diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h= b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h new file mode 100644 index 00000000000..f81135900e8 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h @@ -0,0 +1,69 @@ +/* This file is part of the Vc library. { +Copyright =C2=A9 2017 Matthias Kretz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the names of contributing organizations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS= " AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPL= IED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICE= S; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF T= HIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +}*/ + +#include + +template + inline M + make_mask(const std::initializer_list &init) + { + std::size_t i =3D 0; + M r =3D {}; + for (;;) + { + for (bool x : init) + { + r[i] =3D x; + if (++i =3D=3D M::size()) + { + return r; + } + } + } + } + +template + inline V + make_vec(const std::initializer_list &init, + typename V::value_type inc =3D 0) + { + std::size_t i =3D 0; + V r =3D {}; + typename V::value_type base =3D 0; + for (;;) + { + for (auto x : init) + { + r[i] =3D base + x; + if (++i =3D=3D V::size()) + { + return r; + } + } + base +=3D inc; + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathrefere= nce.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h new file mode 100644 index 00000000000..3e5892c2624 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h @@ -0,0 +1,143 @@ +#include +#include +#include + +template + struct SincosReference + { + T x, s, c; + + std::tuple + as_tuple() const + { return std::tie(x, s, c); } + }; + +template + struct Reference { + T x, ref; + + std::tuple + as_tuple() const + { return std::tie(x, ref); } + }; + +template + struct Array + { + std::size_t size_; + const T *data_; + + Array() + : size_(0), data_(nullptr) {} + + Array(size_t s, const T *p) + : size_(s), data_(p) {} + + const T* + begin() const + { return data_; } + + const T* + end() const + { return data_ + size_; } + + std::size_t + size() const + { return size_; } + }; + +namespace function { + struct sincos{ static constexpr const char *const str =3D "sincos"; }; + struct atan { static constexpr const char *const str =3D "atan"; }; + struct asin { static constexpr const char *const str =3D "asin"; }; + struct acos { static constexpr const char *const str =3D "acos"; }; + struct log { static constexpr const char *const str =3D "ln"; }; + struct log2 { static constexpr const char *const str =3D "log2"; }; + struct log10 { static constexpr const char *const str =3D "log10"; }; +} + +template + struct testdatatype_for_function + { + template + using type =3D Reference; + }; + +template <> + struct testdatatype_for_function + { + template + using type =3D SincosReference; + }; + +template + using testdatatype_for_function_t + =3D typename testdatatype_for_function::template type; + +template + struct StaticDeleter + { + const T *ptr; + + StaticDeleter(const T *p) + : ptr(p) {} + + ~StaticDeleter() + { delete[] ptr; } + }; + +template + inline std::string filename() + { + static_assert(std::is_floating_point::value, ""); + static const auto cache + =3D std::string("reference-") + F::str + + (sizeof(T) =3D=3D 4 && std::__digits_v =3D=3D 24 + && std::__max_exponent_v =3D=3D 128 + ? "-sp" + : (sizeof(T) =3D=3D 8 + && std::__digits_v =3D=3D 53 + && std::__max_exponent_v =3D=3D 1024 + ? "-dp" + : (sizeof(T) =3D=3D 16 && std::__digits_v =3D=3D 64 + && std::__max_exponent_v =3D=3D 16384 + ? "-ep" + : (sizeof(T) =3D=3D 16 && std::__digits_v =3D=3D 113 + && std::__max_exponent_v =3D=3D 16384 + ? "-qp" + : "-unknown")))) + + ".dat"; + return cache; + } + +template > + Array + referenceData() + { + static Array data; + if (data.data_ =3D=3D nullptr) + { + FILE* file =3D std::fopen(filename().c_str(), "rb"); + if (file) + { + std::fseek(file, 0, SEEK_END); + const size_t size =3D std::ftell(file) / sizeof(Ref); + std::rewind(file); + auto mem =3D new Ref[size]; + static StaticDeleter _cleanup(data.data_); + data.size_ =3D std::fread(mem, sizeof(Ref), size, file); + data.data_ =3D mem; + std::fclose(file); + } + else + { + __builtin_fprintf( + stderr, + "%s:%d: the reference data %s does not exist in the current " + "working directory.\n", + __FILE__, __LINE__, filename().c_str()); + __builtin_abort(); + } + } + return data; + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelper= s.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h new file mode 100644 index 00000000000..16c6b287690 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h @@ -0,0 +1,147 @@ +#ifndef VC_TESTS_METAHELPERS_H_ +#define VC_TESTS_METAHELPERS_H_ + +#include +#include +#include + +namespace vir +{ + namespace test + { + template + constexpr bool + operator_is_substitution_failure_impl(float) + { return true; } + + template + constexpr typename std::conditional(), std::declval()))>::type + operator_is_substitution_failure_impl(int) + { return false; } + + template + constexpr bool + operator_is_substitution_failure() + { return operator_is_substitution_failure_impl(int()); } + + template + constexpr auto + sfinae_is_callable_impl(int, F &&f) -> typename std::conditional< + true, std::true_type, + decltype(std::forward(f)(std::declval()...))>::type; + + template + constexpr std::false_type + sfinae_is_callable_impl(float, const F &); + + template + constexpr bool + sfinae_is_callable(F &&) + { + return decltype( + sfinae_is_callable_impl(int(), std::declval()))::value; + } + + template + constexpr auto sfinae_is_callable_t(F &&f) + -> decltype(sfinae_is_callable_impl(int(), std::declval())); + + template + constexpr bool + has_less_bits() + { return std::__digits_v < std::__digits_v; } + + } // namespace test +} // namespace vir + +struct assignment +{ + template + constexpr decltype(std::declval() =3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) =3D std::forward(b))) + { return std::forward(a) =3D std::forward(b); } +}; + +struct bit_shift_left +{ + template + constexpr decltype(std::declval() << std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) << std::forward(b))) + { return std::forward(a) << std::forward(b); } +}; + +struct bit_shift_right +{ + template + constexpr decltype(std::declval() >> std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) >> std::forward(b))) + { return std::forward(a) >> std::forward(b); } +}; + +struct assign_modulus +{ + template + constexpr decltype(std::declval() %=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) %=3D std::forward(b))) + { return std::forward(a) %=3D std::forward(b); } +}; + +struct assign_bit_and +{ + template + constexpr decltype(std::declval() &=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) &=3D std::forward(b))) + { return std::forward(a) &=3D std::forward(b); } +}; + +struct assign_bit_or +{ + template + constexpr decltype(std::declval() |=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) |=3D std::forward(b))) + { return std::forward(a) |=3D std::forward(b); } +}; + +struct assign_bit_xor +{ + template + constexpr decltype(std::declval() ^=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) ^=3D std::forward(b))) + { return std::forward(a) ^=3D std::forward(b); } +}; + +struct assign_bit_shift_left +{ + template + constexpr decltype(std::declval() <<=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) <<=3D std::forward(b))) + { return std::forward(a) <<=3D std::forward(b); } +}; + +struct assign_bit_shift_right +{ + template + constexpr decltype(std::declval() >>=3D std::declval()) + operator()(A &&a, B &&b) const noexcept(noexcept( + std::forward(a) >>=3D std::forward(b))) + { return std::forward(a) >>=3D std::forward(b); } +}; + +template > + constexpr bool is_substitution_failure + =3D vir::test::operator_is_substitution_failure(); + +using vir::test::sfinae_is_callable; + +using vir::test::has_less_bits; + +#endif // VC_TESTS_METAHELPERS_H_ diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.= h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h new file mode 100644 index 00000000000..b7fbaf883bf =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h @@ -0,0 +1,131 @@ +/* This file is part of the Vc library. { +Copyright =C2=A9 2018 Matthias Kretz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the names of contributing organizations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS= " AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPL= IED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICE= S; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF T= HIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +}*/ + +#ifndef VC_TESTS_SIMD_VIEW_H_ +#define VC_TESTS_SIMD_VIEW_H_ + +#include + +_GLIBCXX_SIMD_BEGIN_NAMESPACE + +namespace experimental +{ + namespace imported_begin_end + { + using std::begin; + using std::end; + + template + using begin_type =3D decltype(begin(std::declval())); + + template + using end_type =3D decltype(end(std::declval())); + } // namespace imported_begin_end + + template + class viewer + { + It it; + const End end; + + template + void + for_each_impl(F &&fun, std::index_sequence<0, 1, 2>) + { + for (; it + V::size() <=3D end; it +=3D V::size()) + { + fun(V([&](auto i) { return std::get<0>(it[i].as_tuple()); }), + V([&](auto i) { return std::get<1>(it[i].as_tuple()); }), + V([&](auto i) { return std::get<2>(it[i].as_tuple()); })); + } + if (it !=3D end) + { + fun(V([&](auto i) + { + auto ii =3D it + i < end ? i + 0 : 0; + return std::get<0>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii =3D it + i < end ? i + 0 : 0; + return std::get<1>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii =3D it + i < end ? i + 0 : 0; + return std::get<2>(it[ii].as_tuple()); + })); + } + } + + template + void + for_each_impl(F &&fun, std::index_sequence<0, 1>) + { + for (; it + V::size() <=3D end; it +=3D V::size()) + { + fun(V([&](auto i) { return std::get<0>(it[i].as_tuple()); }), + V([&](auto i) { return std::get<1>(it[i].as_tuple()); })); + } + if (it !=3D end) + { + fun(V([&](auto i) { + auto ii =3D it + i < end ? i + 0 : 0; + return std::get<0>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii =3D it + i < end ? i + 0 : 0; + return std::get<1>(it[ii].as_tuple()); + })); + } + } + + public: + viewer(It _it, End _end) + : it(_it), end(_end) {} + + template + void + for_each(F &&fun) + { + constexpr size_t N + =3D std::tuple_sizeas_tuple())>>::value; + for_each_impl(std::forward(fun), std::make_index_sequence()); + } + }; + + template + viewer, + imported_begin_end::end_type> + simd_view(const Cont &data) + { + using std::begin; + using std::end; + return {begin(data), end(data)}; + } +} // namespace experimental +_GLIBCXX_SIMD_END_NAMESPACE + +#endif // VC_TESTS_SIMD_VIEW_H_ diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_value= s.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h new file mode 100644 index 00000000000..7acbb832900 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h @@ -0,0 +1,366 @@ +#include +#include +#include +#include + +template + std::experimental::simd + iif(std::experimental::simd_mask k, + const typename std::experimental::simd_mask::simd_type& t, + const std::experimental::simd& f) + { + auto r =3D f; + where(k, r) =3D t; + return r; + } + +template + V + epilogue_load(const typename V::value_type* mem, const std::size_t size) + { + const int rem =3D size % V::size(); + return where(V([](int i) { return i; }) < rem, V(0)) + .copy_from(mem + size / V::size() * V::size(), + std::experimental::element_aligned); + } + +template + void + test_values(const std::initializer_list& inputs, + F&&... fun_pack) + { + for (auto it =3D inputs.begin(); it + V::size() <=3D inputs.end(); + it +=3D V::size()) + { + [](auto...) { + }((fun_pack(V(&it[0], std::experimental::element_aligned)), 0)...); + } + [](auto...) { + }((fun_pack(epilogue_load(inputs.begin(), inputs.size())), 0)...); + } + +template + struct RandomValues + { + using T =3D typename V::value_type; + static constexpr bool isfp =3D std::is_floating_point_v; + const std::size_t count; + + std::conditional_t, + std::uniform_real_distribution, + std::uniform_int_distribution> + dist; + + const bool uniform; + + const T abs_max =3D std::__finite_max_v; + + RandomValues(std::size_t count_, T min, T max) + : count(count_), dist(min, max), uniform(true) + { + if constexpr (std::is_floating_point_v) + VERIFY(max - min <=3D std::__finite_max_v); + } + + RandomValues(std::size_t count_) + : count(count_), dist(isfp ? 1 : std::__finite_min_v, + isfp ? 2 : std::__finite_max_v), + uniform(!isfp) + {} + + RandomValues(std::size_t count_, T abs_max_) + : count(count_), dist(isfp ? 1 : -abs_max_, isfp ? 2 : abs_max_), + uniform(!isfp), abs_max(abs_max_) + {} + + template + V + operator()(URBG& gen) + { + if constexpr (!isfp) + return V([&](int) { return dist(gen); }); + else if (uniform) + return V([&](int) { return dist(gen); }); + else + { + auto exp_dist + =3D std::normal_distribution(0.f, + std::__max_exponent_v * .5f); + return V([&](int) { + const T mant =3D dist(gen); + T fp =3D 0; + do { + const int exp =3D exp_dist(gen); + fp =3D std::ldexp(mant, exp); + } while (fp >=3D abs_max || fp <=3D std::__denorm_min_v); + fp =3D gen() & 0x4 ? fp : -fp; + return fp; + }); + } + } + }; + +static std::mt19937 g_mt_gen{0}; + +template + void + test_values(const std::initializer_list& inputs, + RandomValues random, F&&... fun_pack) + { + test_values(inputs, fun_pack...); + for (size_t i =3D 0; i < (random.count + V::size() - 1) / V::size(); += +i) + { + [](auto...) {}((fun_pack(random(g_mt_gen)), 0)...); + } + } + +template + void + test_values_2arg(const std::initializer_list& in= puts, + F&&... fun_pack) + { + for (auto scalar_it =3D inputs.begin(); scalar_it !=3D inputs.end(); + ++scalar_it) + { + for (auto it =3D inputs.begin(); it + V::size() <=3D inputs.end(); + it +=3D V::size()) + { + [](auto...) { + }((fun_pack(V(&it[0], std::experimental::element_aligned), + V(*scalar_it)), + 0)...); + } + [](auto...) { + }((fun_pack(epilogue_load(inputs.begin(), inputs.size()), + V(*scalar_it)), + 0)...); + } + } + +template + void + test_values_2arg(const std::initializer_list& in= puts, + RandomValues random, F&&... fun_pack) + { + test_values_2arg(inputs, fun_pack...); + for (size_t i =3D 0; i < (random.count + V::size() - 1) / V::size(); += +i) + { + [](auto...) {}((fun_pack(random(g_mt_gen), random(g_mt_gen)), 0)...); + } + } + +template + void + test_values_3arg(const std::initializer_list& in= puts, + F&&... fun_pack) + { + for (auto scalar_it1 =3D inputs.begin(); scalar_it1 !=3D inputs.end(); + ++scalar_it1) + { + for (auto scalar_it2 =3D inputs.begin(); scalar_it2 !=3D inputs.end(); + ++scalar_it2) + { + for (auto it =3D inputs.begin(); it + V::size() <=3D inputs.end(); + it +=3D V::size()) + { + [](auto...) { + }((fun_pack(V(&it[0], std::experimental::element_aligned), + V(*scalar_it1), V(*scalar_it2)), + 0)...); + } + [](auto...) { + }((fun_pack(epilogue_load(inputs.begin(), inputs.size()), + V(*scalar_it1), V(*scalar_it2)), + 0)...); + } + } + } + +template + void + test_values_3arg(const std::initializer_list& in= puts, + RandomValues random, F&&... fun_pack) + { + test_values_3arg(inputs, fun_pack...); + for (size_t i =3D 0; i < (random.count + V::size() - 1) / V::size(); += +i) + { + [](auto...) { + }((fun_pack(random(g_mt_gen), random(g_mt_gen), random(g_mt_gen)), + 0)...); + } + } + +#if __GCC_IEC_559 < 2 +// Without IEC559 we consider -0, subnormals, +/-inf, and all NaNs to be +// invalid (potential UB when used or "produced"). This can't use isnormal= (or +// any other classification function), since they know about the UB. +template + typename V::mask_type + isvalid(V x) + { + using namespace std::experimental::parallelism_v2; + using namespace std::experimental::parallelism_v2::__proposed; + using T =3D typename V::value_type; + if constexpr (sizeof(T) <=3D sizeof(double)) + { + using I =3D rebind_simd_t<__int_for_sizeof_t, V>; + const I abs_x =3D __bit_cast(abs(x)); + const I min =3D __bit_cast(V(std::__norm_min_v)); + const I max =3D __bit_cast(V(std::__finite_max_v)); + return static_simd_cast( + __bit_cast(x) =3D=3D 0 || (abs_x >=3D min && abs_x <=3D max)); + } + else + { + const V abs_x =3D abs(x); + const V min =3D std::__norm_min_v; + // Make max non-const static to inhibit constprop. Otherwise the + // compiler might decide `abs_x <=3D max` is constexpr true, by definition + // (-ffinite-math-only) + static V max =3D std::__finite_max_v; + return (x =3D=3D 0 && copysign(V(1), x) =3D=3D V(1)) + || (abs_x >=3D min && abs_x <=3D max); + } + } + +#define MAKE_TESTER_2(name_, reference_) = \ + [&](auto... inputs) { = \ + ((where(!isvalid(inputs), inputs) =3D 1), ...); = \ + const auto totest =3D name_(inputs...); = \ + using R =3D std::remove_const_t; = \ + auto&& expected =3D [&](const auto&... vs) -> const R { = \ + R tmp =3D {}; = \ + for (std::size_t i =3D 0; i < R::size(); ++i) = \ + tmp[i] =3D reference_(vs[i]...); \ + return tmp; = \ + }; = \ + const R expect1 =3D expected(inputs...); = \ + if constexpr (std::is_floating_point_v) = \ + { = \ + ((where(!isvalid(expect1), inputs) =3D 1), ...); \ + const R expect2 =3D expected(inputs...); \ + ((FUZZY_COMPARE(name_(inputs...), expect2) << "\ninputs =3D ") \ + << ... << inputs); \ + } = \ + else = \ + ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(") = \ + << ... << inputs) = \ + << ")"; \ + } + +#define MAKE_TESTER_NOFPEXCEPT(name_) = \ + [&](auto... inputs) { = \ + ((where(!isvalid(inputs), inputs) =3D 1), ...); = \ + using R =3D std::remove_const_t; = \ + auto&& expected =3D [&](const auto&... vs) -> const R { = \ + R tmp =3D {}; = \ + for (std::size_t i =3D 0; i < R::size(); ++i) = \ + tmp[i] =3D std::name_(vs[i]...); \ + return tmp; = \ + }; = \ + const R expect1 =3D expected(inputs...); = \ + if constexpr (std::is_floating_point_v) = \ + { = \ + ((where(!isvalid(expect1), inputs) =3D 1), ...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + auto totest =3D name_(inputs...); \ + asm volatile(""); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + const R expect2 =3D expected(inputs...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + totest =3D name_(inputs...); \ + asm volatile(""); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + ((FUZZY_COMPARE(totest, expect2) << "\n" #name_ "(") << ... << inputs) \ + << ")"; \ + } = \ + else = \ + { = \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + auto totest =3D name_(inputs...); \ + asm volatile(""); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + ((COMPARE(totest, expect1) << "\n" #name_ "(") << ... << inputs) \ + << ")"; \ + } = \ + } + +#else + +#define MAKE_TESTER_2(name_, reference_) = \ + [&](auto... inputs) { = \ + const auto totest =3D name_(inputs...); = \ + using R =3D std::remove_const_t; = \ + auto&& expected =3D [&](const auto&... vs) -> const R { = \ + R tmp =3D {}; = \ + for (std::size_t i =3D 0; i < R::size(); ++i) = \ + tmp[i] =3D reference_(vs[i]...); \ + return tmp; = \ + }; = \ + const R expect1 =3D expected(inputs...); = \ + if constexpr (std::is_floating_point_v) = \ + { = \ + ((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(") \ + << ... << inputs) \ + << ") =3D " << totest << " !=3D " << expect1; = \ + ((where(isnan(expect1), inputs) =3D 0), ...); \ + ((FUZZY_COMPARE(name_(inputs...), expected(inputs...)) \ + << "\nclean =3D ") \ + << ... << inputs); \ + } = \ + else = \ + ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(") = \ + << ... << inputs) = \ + << ")"; \ + } + +#define MAKE_TESTER_NOFPEXCEPT(name_) = \ + [&](auto... inputs) { = \ + std::feclearexcept(FE_ALL_EXCEPT); = \ + auto totest =3D name_(inputs...); = \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") = \ + << ... << inputs) = \ + << ")"; = \ + using R =3D std::remove_const_t; = \ + auto&& expected =3D [&](const auto&... vs) -> const R { = \ + R tmp =3D {}; = \ + for (std::size_t i =3D 0; i < R::size(); ++i) = \ + tmp[i] =3D std::name_(vs[i]...); \ + return tmp; = \ + }; = \ + const R expect1 =3D expected(inputs...); = \ + if constexpr (std::is_floating_point_v) = \ + { = \ + ((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(") \ + << ... << inputs) \ + << ") =3D " << totest << " !=3D " << expect1; = \ + ((where(isnan(expect1), inputs) =3D 0), ...); \ + const R expect2 =3D expected(inputs...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + totest =3D name_(inputs...); \ + asm volatile(""); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + FUZZY_COMPARE(totest, expect2); \ + } = \ + else = \ + { = \ + ((COMPARE(totest, expect1) << "\n" #name_ "(") << ... << inputs) \ + << ")"; \ + } = \ + } + +#endif + +#define MAKE_TESTER(name_) MAKE_TESTER_2(name_, std::name_) diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h b/li= bstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h new file mode 100644 index 00000000000..c1b9e7adb07 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h @@ -0,0 +1,111 @@ +/*{ +Copyright =C2=A9 2011-2018 Matthias Kretz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the names of contributing organizations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS= " AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPL= IED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICE= S; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF T= HIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +}*/ + +#ifndef ULP_H +#define ULP_H + +#include +#include +#include +#include + +namespace vir { + namespace test { + template + R + value_type_impl(int); + + template + T + value_type_impl(float); + + template + using value_type_t =3D decltype(value_type_impl(int())); + + template + inline T + ulp_distance(const T& val_, const T& ref_) + { + if constexpr (std::is_floating_point_v>) + { + const int fp_exceptions =3D std::fetestexcept(FE_ALL_EXCEPT); + T val =3D val_; + T ref =3D ref_; + + T diff =3D T(); + + using std::abs; + using std::fpclassify; + using std::frexp; + using std::isnan; + using std::isinf; + using std::ldexp; + using std::max; + using std::experimental::where; + using TT =3D value_type_t; + + where(ref =3D=3D 0, val) =3D abs(val); + where(ref =3D=3D 0, diff) =3D 1; + where(ref =3D=3D 0, ref) =3D std::__norm_min_v; + where(isinf(ref) && ref =3D=3D val, ref) + =3D 0; // where(val_ =3D=3D ref_) =3D 0 below will fix it up + + where(val =3D=3D 0, ref) =3D abs(ref); + where(val =3D=3D 0, diff) +=3D 1; + where(val =3D=3D 0, val) =3D std::__norm_min_v; + + using I =3D decltype(fpclassify(std::declval())); + I exp =3D {}; + frexp(ref, &exp); + // lower bound for exp must be min_exponent to scale the resul= ting + // difference from a denormal correctly + exp =3D max(exp, I(std::__min_exponent_v)); + diff +=3D ldexp(abs(ref - val), std::__digits_v - exp); + where(val_ =3D=3D ref_ || (isnan(val_) && isnan(ref_)), diff) = =3D T(); + std::feclearexcept(FE_ALL_EXCEPT ^ fp_exceptions); + return diff; + } + else + { + if (val_ > ref_) + return val_ - ref_; + else + return ref_ - val_; + } + } + + template + inline T + ulp_distance_signed(const T& _val, const T& _ref) + { + using std::copysign; + return copysign(ulp_distance(_val, _ref), _val - _ref); + } + } // namespace test +} // namespace vir + +#endif // ULP_H diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h b= /libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h new file mode 100644 index 00000000000..7ec6de7f16b =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h @@ -0,0 +1,336 @@ +#ifndef TESTS_BITS_VERIFY_H_ +#define TESTS_BITS_VERIFY_H_ + +#include +#include +#include +#include "ulp.h" + +#ifdef _GLIBCXX_SIMD_HAVE_NEON +// work around PR89357: +#define alignas(...) __attribute__((aligned(__VA_ARGS__))) +#endif + +using schar =3D signed char; +using uchar =3D unsigned char; +using ushort =3D unsigned short; +using uint =3D unsigned int; +using ulong =3D unsigned long; +using llong =3D long long; +using ullong =3D unsigned long long; +using ldouble =3D long double; +using wchar =3D wchar_t; +using char16 =3D char16_t; +using char32 =3D char32_t; + +template + T + make_value_unknown(const T& x) + { + if constexpr (std::is_constructible_v) + { + const volatile T& y =3D x; + return y; + } + else + { + T y =3D x; + asm("" : "+m"(y)); + return y; + } + } + +class verify +{ + const bool m_failed =3D false; + + template () + << std::declval())> + void + print(const T& x, int) const + { + std::stringstream ss; + ss << x; + __builtin_fprintf(stderr, "%s", ss.str().c_str()); + } + + template + void + print(const T& x, ...) const + { + if constexpr (std::experimental::is_simd_v) + { + std::stringstream ss; + if constexpr (std::is_floating_point_v) + { + ss << '(' << x[0] << " =3D=3D " << std::hexfloat << x[0] + << std::defaultfloat << ')'; + for (unsigned i =3D 1; i < x.size(); ++i) + { + ss << (i % 4 =3D=3D 0 ? ",\n(" : ", (") << x[i] + << " =3D=3D " << std::hexfloat << x[i] << std::defaultfloat + << ')'; + } + } + else + { + ss << +x[0]; + for (unsigned i =3D 1; i < x.size(); ++i) + { + ss << ", " << +x[i]; + } + } + __builtin_fprintf(stderr, "%s", ss.str().c_str()); + } + else if constexpr (std::experimental::is_simd_mask_v) + { + __builtin_fprintf(stderr, (x[0] ? "[1" : "[0")); + for (unsigned i =3D 1; i < x.size(); ++i) + { + __builtin_fprintf(stderr, (x[i] ? "1" : "0")); + } + __builtin_fprintf(stderr, "]"); + } + else + { + print_hex(&x, sizeof(T)); + } + } + + void + print_hex(const void* x, std::size_t n) const + { + __builtin_fprintf(stderr, "0x"); + const auto* bytes =3D static_cast(x); + for (std::size_t i =3D 0; i < n; ++i) + { + __builtin_fprintf(stderr, (i && i % 4 =3D=3D 0) ? "'%02x" : "%02x", + bytes[i]); + } + } + +public: + template + verify(bool ok, size_t ip, const char* file, const int line, + const char* func, const char* cond, const Ts&... extra_info) + : m_failed(!ok) + { + if (m_failed) + { + __builtin_fprintf(stderr, "%s:%d: (%s):\nInstruction Pointer: %x\n" + "Assertion '%s' failed.\n", + file, line, func, ip, cond); + (print(extra_info, int()), ...); + } + } + + ~verify() + { + if (m_failed) + { + __builtin_fprintf(stderr, "\n"); + __builtin_abort(); + } + } + + template + const verify& + operator<<(const T& x) const + { + if (m_failed) + { + print(x, int()); + } + return *this; + } + + template + const verify& + on_failure(const Ts&... xs) const + { + if (m_failed) + (print(xs, int()), ...); + return *this; + } + + [[gnu::always_inline]] static inline size_t + get_ip() + { + size_t _ip =3D 0; +#ifdef __x86_64__ + asm volatile("lea 0(%%rip),%0" : "=3Dr"(_ip)); +#elif defined __i386__ + asm volatile("1: movl $1b,%0" : "=3Dr"(_ip)); +#elif defined __arm__ + asm volatile("mov %0,pc" : "=3Dr"(_ip)); +#elif defined __aarch64__ + asm volatile("adr %0,." : "=3Dr"(_ip)); +#endif + return _ip; + } +}; + +#if __FLT_EVAL_METHOD__ !=3D 0 +template + [[gnu::always_inline]] inline decltype(auto) + force_fp_truncation(const T& x) + { + namespace stdx =3D std::experimental; + if constexpr (stdx::is_simd_v) + { + using U =3D typename T::value_type; + if constexpr (std::is_floating_point_v + && sizeof(U) <=3D 8 && (sizeof(T) < 16 || std::is_same_v< + T, stdx::fixed_size_simd>)) + { + T y =3D x; + asm("" : "+m"(y)); + return y; + } + else + return x; + } + else if constexpr (std::is_floating_point_v && sizeof(T) <=3D 8) + { + T y =3D x; + asm("" : "+m"(y)); + return y; + } + else + return x; + } + +#define COMPARE(_a, _b) = \ + [&](auto&& _aa, auto&& _bb) { = \ + return verify(std::experimental::all_of(_aa =3D=3D _bb), verify::get_i= p(), \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + "all_of(" #_a " =3D=3D " #_b ")", #_a " =3D ", _aa, \ + "\n" #_b " =3D ", _bb); \ + }(force_fp_truncation(_a), force_fp_truncation(_b)) +#else +#define COMPARE(_a, _b) = \ + [&](auto&& _aa, auto&& _bb) { = \ + return verify(std::experimental::all_of(_aa =3D=3D _bb), verify::get_i= p(), \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + "all_of(" #_a " =3D=3D " #_b ")", #_a " =3D ", _aa, \ + "\n" #_b " =3D ", _bb); \ + }((_a), (_b)) +#endif + +#define VERIFY(_test) = \ + verify(_test, verify::get_ip(), __FILE__, __LINE__, __PRETTY_FUNCTION__,= \ + #_test) + + // ulp_distance_signed can raise FP exceptions and thus must be conditio= nally + // executed +#define ULP_COMPARE(_a, _b, _allowed_distance) = \ + [&](auto&& _aa, auto&& _bb) { = \ + const bool success =3D std::experimental::all_of( = \ + vir::test::ulp_distance(_aa, _bb) <=3D (_allowed_distance)); = \ + return verify(success, verify::get_ip(), __FILE__, __LINE__, = \ + __PRETTY_FUNCTION__, "all_of(" #_a " ~~ " #_b ")", \ + #_a " =3D ", _aa, "\n" #_b " =3D ", _bb, "\ndistance =3D ", \ + success ? 0 : vir::test::ulp_distance_signed(_aa, _bb)); \ + }((_a), (_b)) + +namespace vir { + namespace test + { + template + inline T _S_fuzzyness =3D 0; + + template + void + setFuzzyness(T x) + { _S_fuzzyness =3D x; } + } // namespace test +} // namespace vir + +#define FUZZY_COMPARE(_a, _b) = \ + ULP_COMPARE( = \ + _a, _b, = \ + vir::test::_S_fuzzyness= >) + +template + void + test(); + +template + void + invoke_test(...) + {} + +template + void + invoke_test(int) + { + test(); + __builtin_fprintf(stderr, "PASS: %s\n", __PRETTY_FUNCTION__); + } + +template + void + iterate_abis() + { + using namespace std::experimental::parallelism_v2; +#ifndef EXTENDEDTESTS + invoke_test>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 0 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 1 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 2 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 3 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 4 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 5 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 6 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 7 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS =3D=3D 8 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#endif + } + +int main() +{ + iterate_abis<_GLIBCXX_SIMD_TESTTYPE>(); + return 0; +} + +#endif // TESTS_BITS_VERIFY_H_ diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc new file mode 100644 index 00000000000..529280d87d4 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc @@ -0,0 +1,87 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +enum unscoped_enum +{ foo }; + +enum class scoped_enum +{ bar }; + +struct convertible +{ + operator int(); + operator float(); +}; + +template + void + test() + { + using T =3D typename V::value_type; + VERIFY(std::experimental::is_simd_v); + VERIFY(std::experimental::is_abi_tag_v); + + { + V x; // not initialized + x =3D V{}; // default broadcasts 0 + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + x =3D V(); // default broadcasts 0 + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + x =3D 0; + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(T(x[i]), T(0)) << "i =3D " << i; + COMPARE(x[i], T(0)) << "i =3D " << i; + } + } + + V x =3D 3; + V y =3D T(0); + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(x[i], T(3)) << "i =3D " << i; + COMPARE(y[i], T(0)) << "i =3D " << i; + } + y =3D 3; + COMPARE(x, y); + + VERIFY(!(is_substitution_failure) ); + VERIFY((is_substitution_failure) ); + COMPARE((is_substitution_failure), + (!std::is_convertible::value)); + COMPARE((is_substitution_failure), + (sizeof(long double) > sizeof(T) || std::is_integral::value)); + COMPARE((is_substitution_failure), + (sizeof(double) > sizeof(T) || std::is_integral::value)); + COMPARE((is_substitution_failure), + (sizeof(float) > sizeof(T) || std::is_integral::value)); + COMPARE((is_substitution_failure), + (has_less_bits() || std::is_unsigned::value)); + COMPARE((is_substitution_failure), + (has_less_bits())); + COMPARE((is_substitution_failure), + (has_less_bits() || std::is_unsigned::value)); + COMPARE((is_substitution_failure), + (has_less_bits())); + // int broadcast *always* works: + VERIFY(!(is_substitution_failure) ); + // uint broadcast works for any unsigned T: + COMPARE((is_substitution_failure), + (!std::is_unsigned::value && has_less_bits())); + COMPARE((is_substitution_failure), + (has_less_bits() || std::is_unsigned::value)); + COMPARE((is_substitution_failure), + (has_less_bits())); + COMPARE((is_substitution_failure), + (has_less_bits() || std::is_unsigned::value)); + COMPARE((is_substitution_failure), + (has_less_bits())); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc b/libs= tdc++-v3/testsuite/experimental/simd/tests/casts.cc new file mode 100644 index 00000000000..e2c0b108879 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc @@ -0,0 +1,152 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/conversions.h" + +using std::experimental::simd_cast; +using std::experimental::static_simd_cast; + +template + struct gen_cast + { + std::array data; + + template + gen_cast(const V& v) + { + for (size_t i =3D 0; i < V::size(); ++i) + { + data[i] =3D static_cast(v[i]); + } + } + + template + constexpr T + operator()(I) + { return data[I::value]; } + }; + +template + struct gen_seq_t + { + using From =3D typename V::value_type; + const size_t N =3D cvt_input_data.size(); + size_t offset =3D 0; + + constexpr void + operator++() + { offset +=3D V::size(); } + + explicit constexpr operator bool() const + { return offset < N; } + + template + constexpr From + operator()(I) const + { + size_t i =3D I::value + offset; + return i < N ? cvt_input_data[i] : From(i); + } + }; + +template + struct foo + { + template + auto + operator()(const T& v) -> decltype(simd_cast(v)); + }; + +template + void + casts() + { + using From =3D typename V::value_type; + constexpr auto N =3D V::size(); + if constexpr (N <=3D std::experimental::simd_abi::max_fixed_size) + { + using W =3D std::experimental::fixed_size_simd; + + if constexpr (std::is_integral_v) + { + using A =3D typename V::abi_type; + using TU =3D std::make_unsigned_t; + using TS =3D std::make_signed_t; + COMPARE(typeid(static_simd_cast(V())), + typeid(std::experimental::simd)); + COMPARE(typeid(static_simd_cast(V())), + typeid(std::experimental::simd)); + } + + using is_simd_cast_allowed + =3D decltype(vir::test::sfinae_is_callable_t(foo())); + + COMPARE(is_simd_cast_allowed::value, + std::__digits::value <=3D std::__digits::value + && std::__finite_max::value + <=3D std::__finite_max::value + && !(std::is_signed::value + && std::is_unsigned::value)); + + if constexpr (is_simd_cast_allowed::value) + { + for (gen_seq_t gen_seq; gen_seq; ++gen_seq) + { + const V seq(gen_seq); + COMPARE(simd_cast(seq), seq); + COMPARE(simd_cast(seq), W(gen_cast(seq))) + << "seq =3D " << seq; + auto test =3D simd_cast(seq); + // decltype(test) is not W if + // a) V::abi_type is not fixed_size and + // b.1) V::value_type and To are integral and of equal rank or + // b.2) V::value_type and To are equal + COMPARE(test, decltype(test)(gen_cast(seq))); + if (std::is_same::value) + { + COMPARE(typeid(decltype(test)), typeid(V)); + } + } + } + + for (gen_seq_t gen_seq; gen_seq; ++gen_seq) + { + const V seq(gen_seq); + COMPARE(static_simd_cast(seq), seq); + COMPARE(static_simd_cast(seq), W(gen_cast(seq))) << '\n' + << seq; + auto test =3D static_simd_cast(seq); + // decltype(test) is not W if + // a) V::abi_type is not fixed_size and + // b.1) V::value_type and To are integral and of equal rank or + // b.2) V::value_type and To are equal + COMPARE(test, decltype(test)(gen_cast(seq))); + if (std::is_same::value) + { + COMPARE(typeid(decltype(test)), typeid(V)); + } + } + } + } + +template + void + test() + { + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + casts(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc b= /libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc new file mode 100644 index 00000000000..87a80308ae9 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc @@ -0,0 +1,89 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" +#include + +template + auto + verify_no_fp_exceptions(F&& fun) + { + std::feclearexcept(FE_ALL_EXCEPT); + auto r =3D fun(); + COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0); + return r; + } + +#define NOFPEXCEPT(...) verify_no_fp_exceptions([&]() { return __VA_ARGS__= ; }) + +template + void + test() + { + using T =3D typename V::value_type; + using intv =3D std::experimental::fixed_size_simd; + constexpr T inf =3D std::__infinity_v; + constexpr T denorm_min =3D std::__infinity_v; + constexpr T nan =3D std::__quiet_NaN_v; + constexpr T max =3D std::__finite_max_v; + constexpr T norm_min =3D std::__norm_min_v; + test_values( + {0., 1., -1., +#if __GCC_IEC_559 >=3D 2 + -0., inf, -inf, denorm_min, -denorm_min, nan, + norm_min * 0.9, -norm_min * 0.9, +#endif + max, -max, norm_min, -norm_min + }, + [](const V input) { + COMPARE(NOFPEXCEPT(isfinite(input)), + !V([&](auto i) { return std::isfinite(input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(isinf(input)), + !V([&](auto i) { return std::isinf(input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(isnan(input)), + !V([&](auto i) { return std::isnan(input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(isnormal(input)), + !V([&](auto i) { return std::isnormal(input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(signbit(input)), + !V([&](auto i) { return std::signbit(input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(isunordered(input, V())), + !V([&](auto i) { return std::isunordered(input[i], 0) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(isunordered(V(), input)), + !V([&](auto i) { return std::isunordered(0, input[i]) ? 0 : 1; })) + << input; + COMPARE(NOFPEXCEPT(fpclassify(input)), + intv([&](auto i) { return std::fpclassify(input[i]); })) + << input; + }); +#ifdef __SUPPORT_SNAN__ + const V snan =3D std::__signaling_NaN_v; + COMPARE(isfinite(snan), + !V([&](auto i) { return std::isfinite(snan[i]) ? 0 : 1; })) + << snan; + COMPARE(isinf(snan), !V([&](auto i) { return std::isinf(snan[i]) ? 0 := 1; })) + << snan; + COMPARE(isnan(snan), !V([&](auto i) { return std::isnan(snan[i]) ? 0 := 1; })) + << snan; + COMPARE(isnormal(snan), + !V([&](auto i) { return std::isnormal(snan[i]) ? 0 : 1; })) + << snan; + COMPARE(signbit(snan), + !V([&](auto i) { return std::signbit(snan[i]) ? 0 : 1; })) + << snan; + COMPARE(isunordered(snan, V()), + !V([&](auto i) { return std::isunordered(snan[i], 0) ? 0 : 1; })) + << snan; + COMPARE(isunordered(V(), snan), + !V([&](auto i) { return std::isunordered(0, snan[i]) ? 0 : 1; })) + << snan; + COMPARE(fpclassify(snan), + intv([&](auto i) { return std::fpclassify(snan[i]); })) + << snan; +#endif + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc b/libs= tdc++-v3/testsuite/experimental/simd/tests/frexp.cc new file mode 100644 index 00000000000..1f9b30162cb =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc @@ -0,0 +1,68 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + using int_v =3D std::experimental::fixed_size_simd; + using T =3D typename V::value_type; + constexpr auto denorm_min =3D std::__denorm_min_v; + constexpr auto norm_min =3D std::__norm_min_v; + constexpr auto max =3D std::__finite_max_v; + constexpr auto nan =3D std::__quiet_NaN_v; + constexpr auto inf =3D std::__infinity_v; + test_values( + {0, 0.25, 0.5, 1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, = 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 31, -0., -0.25, -0.5, -= 1, + -3, -4, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, + -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -32, -31, +#if __GCC_IEC_559 >=3D 2 + denorm_min, -denorm_min, norm_min / 2, -norm_min / 2, +#endif + max, -max, max * 0.123f, -max * 0.123f}, + [](const V input) { + V expectedFraction; + const int_v expectedExponent([&](auto i) { + int exp; + expectedFraction[i] =3D std::frexp(input[i], &exp); + return exp; + }); + int_v exponent =3D {}; + const V fraction =3D frexp(input, &exponent); + COMPARE(fraction, expectedFraction) << ", input =3D " << input + << ", delta: " << fraction - expectedFraction; + COMPARE(exponent, expectedExponent) + << "\ninput: " << input << ", fraction: " << fraction; + }); +#ifdef __STDC_IEC_559__ + test_values( + // If x is a NaN, a NaN is returned, and the value of *exp is unspec= ified. + // + // If x is positive infinity (negative infinity), positive infi= nity + // (negative infinity) is returned, and the value of *exp is unspeci= fied. + // This behavior is only guaranteed with C's Annex F when __STDC_IEC= _559__ + // is defined. + {nan, inf, -inf, denorm_min, denorm_min * 1.72, -denorm_min, + -denorm_min * 1.72, 0., -0., 1, -1}, + [](const V input) { + const V expectedFraction([&](auto i) { + int exp; + return std::frexp(input[i], &exp); + }); + int_v exponent =3D {}; + const V fraction =3D frexp(input, &exponent); + COMPARE(isnan(fraction), isnan(expectedFraction)) + << fraction << ", input =3D " << input + << ", delta: " << fraction - expectedFraction; + COMPARE(isinf(fraction), isinf(expectedFraction)) + << fraction << ", input =3D " << input + << ", delta: " << fraction - expectedFraction; + COMPARE(signbit(fraction), signbit(expectedFraction)) + << fraction << ", input =3D " << input + << ", delta: " << fraction - expectedFraction; + }); +#endif + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/generator.cc new file mode 100644 index 00000000000..62ec716c82d =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc @@ -0,0 +1,41 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +template + struct call_generator + { + template + auto + operator()(const F& f) -> decltype(V(f)); + }; + +using schar =3D signed char; +using uchar =3D unsigned char; +using ullong =3D unsigned long long; + +template + void + test() + { + using T =3D typename V::value_type; + V x([](int) { return T(1); }); + COMPARE(x, V(1)); + // unconditionally returns int from generator lambda + x =3D V([](int) { return 1; }); + COMPARE(x, V(1)); + x =3D V([](auto i) { return T(i); }); + COMPARE(x, V([](T i) { return i; })); + + VERIFY((// that int always works + sfinae_is_callable(call_generator()))); + COMPARE(sfinae_is_callable(call_generator()), + std::is_signed::value); + COMPARE(sfinae_is_callable(call_generator()), + !(std::is_signed_v && sizeof(T) <=3D sizeof(uchar))); + COMPARE(sfinae_is_callable(call_generator()), + (std::is_floating_point::value)); + + COMPARE(sfinae_is_callable(call_generator()), + std::__finite_max_v >=3D std::__finite_max_v + && std::__digits_v >=3D std::__digits_v); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc b= /libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc new file mode 100644 index 00000000000..330a79400ee =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc @@ -0,0 +1,134 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +// 3-arg std::hypot needs to be fixed, this is a better reference: +template + [[gnu::optimize("-fno-unsafe-math-optimizations")]] + T + hypot3(T x, T y, T z) + { + x =3D std::abs(x); + y =3D std::abs(y); + z =3D std::abs(z); + if (std::isinf(x) || std::isinf(y) || std::isinf(z)) + return std::__infinity_v; + else if (std::isnan(x) || std::isnan(y) || std::isnan(z)) + return std::__quiet_NaN_v; + else if (x =3D=3D y && y =3D=3D z) + return x * std::sqrt(T(3)); + else if (z =3D=3D 0 && y =3D=3D 0) + return x; + else if (x =3D=3D 0 && z =3D=3D 0) + return y; + else if (x =3D=3D 0 && y =3D=3D 0) + return z; + else + { + T hi =3D std::max(std::max(x, y), z); + T lo0 =3D std::min(std::max(x, y), z); + T lo1 =3D std::min(x, y); + int e =3D 0; + hi =3D std::frexp(hi, &e); + lo0 =3D std::ldexp(lo0, -e); + lo1 =3D std::ldexp(lo1, -e); + T lo =3D lo0 * lo0 + lo1 * lo1; + return std::ldexp(std::sqrt(hi * hi + lo), e); + } + } + +template + void + test() + { + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(2); // because of the bad referen= ce + + using T =3D typename V::value_type; + test_values_3arg( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, + std::__infinity_v, + -std::__infinity_v, + std::__norm_min_v / 3, + -0., + std::__denorm_min_v, +#endif + 0., + 1., + -1., + std::__norm_min_v, + -std::__norm_min_v, + 2., + -2., + std::__finite_max_v / 5, + std::__finite_max_v / 3, + std::__finite_max_v / 2, + -std::__finite_max_v / 5, + -std::__finite_max_v / 3, + -std::__finite_max_v / 2, +#ifdef __FAST_MATH__ + // fast-math hypot is imprecise for the max exponent + }, + {100000, std::__finite_max_v / 2}, +#else + std::__finite_max_v, -std::__finite_max_v}, + {100000}, +#endif + MAKE_TESTER_2(hypot, hypot3)); +#if !__FINITE_MATH_ONLY__ + COMPARE(hypot(V(std::__finite_max_v), V(std::__finite_max_v), V(= )), + V(std::__infinity_v)); + COMPARE(hypot(V(std::__finite_max_v), V(), V(std::__finite_max_v= )), + V(std::__infinity_v)); + COMPARE(hypot(V(), V(std::__finite_max_v), V(std::__finite_max_v= )), + V(std::__infinity_v)); +#endif + COMPARE(hypot(V(std::__norm_min_v), V(std::__norm_min_v), + V(std::__norm_min_v)), + V(std::__norm_min_v * std::sqrt(T(3)))); + auto&& hypot3_test + =3D [](auto a, auto b, auto c) -> decltype(hypot(a, b, c)) { return = {}; }; + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY((sfinae_is_callable(hypot3_test))); + VERIFY(!(sfinae_is_callable(hypot3_test))); + VERIFY(!(sfinae_is_callable(hypot3_test))); + VERIFY(!(sfinae_is_callable(hypot3_test))); + + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + test_values_3arg( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, std::__infinity_v, -std::__infinity_v, -0., + std::__norm_min_v / 3, std::__denorm_min_v, +#endif + 0., std::__norm_min_v, std::__finite_max_v}, + {10000, -std::__finite_max_v / 2, std::__finite_max_v / 2}, + MAKE_TESTER(fma)); + auto&& fma_test + =3D [](auto a, auto b, auto c) -> decltype(fma(a, b, c)) { return {}= ; }; + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((sfinae_is_callable(fma_test))); + VERIFY((!sfinae_is_callable(fma_test))); + VERIFY((!sfinae_is_callable(fma_test))); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/integer_operato= rs.cc b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc new file mode 100644 index 00000000000..9205d865aed =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc @@ -0,0 +1,218 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include "bits/verify.h" +#include "bits/make_vec.h" +#include "bits/metahelpers.h" + +template + void + for_constexpr(F&& fun) + { + if constexpr (Begin <=3D End) + { + fun(std::integral_constant()); + if constexpr (Begin < End) + { + for_constexpr(static_cast(fun)); + } + } + } + +template + void + test() + { + using T =3D typename V::value_type; + if constexpr (std::is_integral_v) + { + constexpr int nbits(sizeof(T) * __CHAR_BIT__); + constexpr int n_promo_bits + =3D std::max(nbits, int(sizeof(int) * __CHAR_BIT__)); + + // complement + COMPARE(~V(), V(~T())); + COMPARE(~V(~T()), V()); + + { // modulus + V x =3D make_vec({3, 4}, 2); + COMPARE(x % x, V(0)); + V y =3D x - 1; + COMPARE(x % y, V(1)); + y =3D x + 1; + COMPARE(x % y, x); + if (std::is_signed::value) + { + x =3D -x; + COMPARE(x % y, x); + x =3D -y; + COMPARE(x % y, V(0)); + x =3D x - 1; + COMPARE(x % y, V(-1)); + x %=3D y; + COMPARE(x, V(-1)); + } + } + + { // bit_and + V x =3D make_vec({3, 4, 5}, 8); + COMPARE(x & x, x); + COMPARE(x & ~x, V()); + COMPARE(x & V(), V()); + COMPARE(V() & x, V()); + V y =3D make_vec({1, 5, 3}, 8); + COMPARE(x & y, make_vec({1, 4, 1}, 8)); + x &=3D y; + COMPARE(x, make_vec({1, 4, 1}, 8)); + } + + { // bit_or + V x =3D make_vec({3, 4, 5}, 8); + COMPARE(x | x, x); + COMPARE(x | ~x, ~V()); + COMPARE(x | V(), x); + COMPARE(V() | x, x); + V y =3D make_vec({1, 5, 3}, 8); + COMPARE(x | y, make_vec({3, 5, 7}, 8)); + x |=3D y; + COMPARE(x, make_vec({3, 5, 7}, 8)); + } + + { // bit_xor + V x =3D make_vec({3, 4, 5}, 8); + COMPARE(x ^ x, V()); + COMPARE(x ^ ~x, ~V()); + COMPARE(x ^ V(), x); + COMPARE(V() ^ x, x); + V y =3D make_vec({1, 5, 3}, 8); + COMPARE(x ^ y, make_vec({2, 1, 6}, 0)); + x ^=3D y; + COMPARE(x, make_vec({2, 1, 6}, 0)); + } + + { // bit_shift_left + // Note: + // - negative RHS or RHS >=3D max(#bits(T), #bits(int)) is UB + // - negative LHS is UB + // - shifting into (or over) the sign bit is UB + // - unsigned LHS overflow is modulo arithmetic + COMPARE(V() << 1, V()); + for (int i =3D 0; i < nbits - 1; ++i) + { + COMPARE(V(1) << i, V(T(1) << i)) << "i: " << i; + } + for_constexpr( + [](auto shift_ic) { + constexpr int shift =3D shift_ic; + const V seq =3D make_value_unknown(V([&](T i) { + if constexpr (std::is_signed_v) + { + const T max =3D std::__finite_max_v >> shift; + return max =3D=3D 0 ? 1 : (std::abs(max - i) % max) + 1; + } + else + { + return ~T() - i; + } + })); + const V ref([&](T i) { return T(seq[i] << shift); }); + COMPARE(seq << shift, ref) << "seq: " << seq + << ", shift: " << shift; + COMPARE(seq << make_value_unknown(shift), ref) + << "seq: " << seq << ", shift: " << shift; + }); + { + V seq =3D make_vec({0, 1}, nbits - 2); + seq %=3D nbits - 1; + COMPARE(make_vec({0, 1}, 0) << seq, + V([&](auto i) { return T(T(i & 1) << seq[i]); })) + << "seq =3D " << seq; + COMPARE(make_vec({1, 0}, 0) << seq, + V([&](auto i) { return T(T(~i & 1) << seq[i]); })); + COMPARE(V(1) << seq, V([&](auto i) { return T(T(1) << seq[i]); })); + } + if (std::is_unsigned::value) + { + constexpr int shift_count =3D nbits - 1; + COMPARE(V(1) << shift_count, V(T(1) << shift_count)); + constexpr T max =3D // avoid overflow warning in the last COMPARE + std::is_unsigned::value ? std::__finite_max_v : T(1); + COMPARE(V(max) << shift_count, V(max << shift_count)) + << "shift_count: " << shift_count; + } + } + + { // bit_shift_right + // Note: + // - negative LHS is implementation defined + // - negative RHS or RHS >=3D #bits is UB + // - no other UB + COMPARE(V(~T()) >> V(0), V(~T())); + COMPARE(V(~T()) >> V(make_value_unknown(0)), V(~T())); + for (int s =3D 1; s < nbits; ++s) + { + COMPARE(V(~T()) >> V(s), V(T(~T()) >> s)) << "s: " << s; + } + for (int s =3D 1; s < nbits; ++s) + { + COMPARE(V(~T(1)) >> V(s), V(T(~T(1)) >> s)) << "s: " << s; + } + COMPARE(V(0) >> V(1), V(0)); + COMPARE(V(1) >> V(1), V(0)); + COMPARE(V(2) >> V(1), V(1)); + COMPARE(V(3) >> V(1), V(1)); + COMPARE(V(7) >> V(2), V(1)); + for (int j =3D 0; j < 100; ++j) + { + const V seq([&](auto i) -> T { return (j + i) % n_promo_bits; }); + COMPARE(V(1) >> seq, V([&](auto i) { return T(T(1) >> seq[i]); })) + << "seq =3D " << seq; + COMPARE(make_value_unknown(V(1)) >> make_value_unknown(seq), + V([&](auto i) { return T(T(1) >> seq[i]); })) + << "seq =3D " << seq; + } + for_constexpr([](auto shift_ic) { + constexpr int shift =3D shift_ic; + const V seq =3D make_value_unknown(V([&](int i) { + using U =3D std::make_unsigned_t; + return T(~U() >> (i % 32)); + })); + const V ref([&](T i) { return T(seq[i] >> shift); }); + COMPARE(seq >> shift, ref) + << "seq: " << seq << ", shift: " << shift; + COMPARE(seq >> make_value_unknown(shift), ref) + << "seq: " << seq << ", shift: " << shift; + }); + } + } + else + { + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_sc= albln_modf.cc b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn= _scalbln_modf.cc new file mode 100644 index 00000000000..e8a519612e8 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_m= odf.cc @@ -0,0 +1,152 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T =3D typename V::value_type; + + // See https://sourceware.org/bugzilla/show_bug.cgi?id=3D18031 + const bool modf_is_broken =3D [] { + volatile T x =3D T(5e20) / 7; + T tmp; + return std::fabs(std::modf(x, &tmp)) >=3D 1; + }(); + if (modf_is_broken) + __builtin_fprintf(stderr, + "NOTE: Skipping modf because std::modf is broken.\n"); + + test_values( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, + std::__infinity_v, + -std::__infinity_v, + -0., + std::__denorm_min_v, + std::__norm_min_v / 3, + -std::__denorm_min_v, + -std::__norm_min_v / 3, +#endif + +0., + +1.3, + -1.3, + 2.1, + -2.1, + 0.99, + 0.9, + -0.9, + -0.99, + std::__norm_min_v, + std::__finite_max_v, + -std::__norm_min_v, + -std::__finite_max_v}, + {10000}, + [](const V input) { + for (int exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000}) + { + const auto totest =3D ldexp(input, exp); + using R =3D std::remove_const_t; + auto&& expected =3D [&](const auto& v) -> const R { + R tmp =3D {}; + using std::ldexp; + for (std::size_t i =3D 0; i < R::size(); ++i) + { + tmp[i] =3D ldexp(v[i], exp); + } + return tmp; + }; + const R expect1 =3D expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "ldexp(" << input << ", " << exp << ") =3D " << totest + << " !=3D " << expect1; + FUZZY_COMPARE(ldexp(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean =3D " << iif(isnan(expect1), 0, input); + } + }, + [](const V input) { + for (int exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000}) + { + const auto totest =3D scalbn(input, exp); + using R =3D std::remove_const_t; + auto&& expected =3D [&](const auto& v) -> const R { + R tmp =3D {}; + using std::scalbn; + for (std::size_t i =3D 0; i < R::size(); ++i) + { + tmp[i] =3D scalbn(v[i], exp); + } + return tmp; + }; + const R expect1 =3D expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "scalbn(" << input << ", " << exp << ") =3D " << totest + << " !=3D " << expect1; + FUZZY_COMPARE(scalbn(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean =3D " << iif(isnan(expect1), 0, input); + } + }, + [](const V input) { + for (long exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000}) + { + const auto totest =3D scalbln(input, exp); + using R =3D std::remove_const_t; + auto&& expected =3D [&](const auto& v) -> const R { + R tmp =3D {}; + using std::scalbln; + for (std::size_t i =3D 0; i < R::size(); ++i) + { + tmp[i] =3D scalbln(v[i], exp); + } + return tmp; + }; + const R expect1 =3D expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "scalbln(" << input << ", " << exp << ") =3D " << totest + << " !=3D " << expect1; + FUZZY_COMPARE(scalbln(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean =3D " << iif(isnan(expect1), 0, input); + } + }, + [modf_is_broken](const V input) { + if (modf_is_broken) + return; + V integral =3D {}; + const V totest =3D modf(input, &integral); + auto&& expected =3D [&](const auto& v) -> std::pair { + std::pair tmp =3D {}; + using std::modf; + for (std::size_t i =3D 0; i < V::size(); ++i) + { + typename V::value_type tmp2; + tmp.first[i] =3D modf(v[i], &tmp2); + tmp.second[i] =3D tmp2; + } + return tmp; + }; + const auto expect1 =3D expected(input); +#ifdef __STDC_IEC_559__ + COMPARE(isnan(totest), isnan(expect1.first)) + << "modf(" << input << ", iptr) =3D " << totest << " !=3D " << expect1; + COMPARE(isnan(integral), isnan(expect1.second)) + << "modf(" << input << ", iptr) =3D " << totest << " !=3D " << expect1; + COMPARE(isnan(totest), isnan(integral)) + << "modf(" << input << ", iptr) =3D " << totest << " !=3D " << expect1; + const V clean =3D iif(isnan(totest), V(), input); +#else + const V clean =3D iif(isnormal(input), input, V()); +#endif + const auto expect2 =3D expected(clean); + COMPARE(modf(clean, &integral), expect2.first) << "\nclean =3D " << clean; + COMPARE(integral, expect2.second); + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc new file mode 100644 index 00000000000..329c89688ed =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc @@ -0,0 +1,212 @@ +#include "bits/verify.h" +#include "bits/make_vec.h" +#include "bits/conversions.h" + +template + void + load_store() + { + // types, tags, and constants + using T =3D typename V::value_type; + auto&& gen =3D make_vec; + using std::experimental::element_aligned; + using std::experimental::vector_aligned; + + // stride_alignment: consider V::size() =3D=3D 6. The only reliable al= ignment is + // 2 * sizeof(U). I.e. if the first address is aligned to 8 * sizeof(U= ), + // then the next address is 6 * sizeof(U) larger, thus only aligned to= 2 * + // sizeof(U). + // =3D> the LSB determines the stride alignment + constexpr size_t stride_alignment =3D size_t(1) << __builtin_ctz(V::si= ze()); + using stride_aligned_t =3D std::conditional_t< + V::size() =3D=3D stride_alignment, decltype(vector_aligned), + std::experimental::overaligned_tag>; + constexpr stride_aligned_t stride_aligned =3D {}; + constexpr size_t alignment + =3D 2 * std::experimental::memory_alignment_v; + constexpr auto overaligned =3D std::experimental::overaligned; + const V indexes_from_0([](auto i) { return i; }); + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(indexes_from_0[i], T(i)); + } + + // loads + cvt_inputs test_values; + + constexpr auto mem_size + =3D test_values.size() > 3 * V::size() ? test_values.size() : 3 * V:= :size(); + alignas(std::experimental::memory_alignment_v * 2) U mem[mem_siz= e] + =3D {}; + alignas(std::experimental::memory_alignment_v * 2) + T reference[mem_size] + =3D {}; + for (std::size_t i =3D 0; i < test_values.size(); ++i) + { + const U value =3D test_values[i]; + mem[i] =3D value; + reference[i] =3D static_cast(value); + } + for (std::size_t i =3D test_values.size(); i < mem_size; ++i) + { + mem[i] =3D U(i); + reference[i] =3D mem[i]; + } + + V x(&mem[V::size()], stride_aligned); + auto&& compare =3D [&](const std::size_t offset) { + static int n =3D 0; + const V ref(&reference[offset], element_aligned); + for (auto i =3D 0ul; i < V::size(); ++i) + { + if (is_conversion_undefined(mem[i + offset])) + { + continue; + } + COMPARE(x[i], reference[i + offset]) + << "\nbefore conversion: " << mem[i + offset] + << "\n offset =3D " << offset << "\n x =3D " << x + << "\nreference =3D " << ref << "\nx =3D=3D ref =3D " << (x =3D=3D r= ef) + << "\ncall no. " << n; + } + ++n; + }; + compare(V::size()); + x =3D V{mem, overaligned}; + compare(0); + x =3D {&mem[1], element_aligned}; + compare(1); + + x.copy_from(&mem[V::size()], stride_aligned); + compare(V::size()); + x.copy_from(&mem[1], element_aligned); + compare(1); + x.copy_from(mem, vector_aligned); + compare(0); + + for (std::size_t i =3D 0; i < mem_size - V::size(); ++i) + { + x.copy_from(&mem[i], element_aligned); + compare(i); + } + + for (std::size_t i =3D 0; i < test_values.size(); ++i) + { + mem[i] =3D U(i); + } + x =3D indexes_from_0; + using M =3D typename V::mask_type; + const M alternating_mask =3D make_mask({0, 1}); + where(alternating_mask, x).copy_from(&mem[V::size()], stride_aligned); + + const V indexes_from_size =3D gen({T(V::size())}, 1); + COMPARE(x =3D=3D indexes_from_size, alternating_mask) + << "x: " << x << "\nindexes_from_size: " << indexes_from_size; + COMPARE(x =3D=3D indexes_from_0, !alternating_mask); + where(alternating_mask, x).copy_from(&mem[1], element_aligned); + + const V indexes_from_1 =3D gen({1, 2, 3, 4}, 4); + COMPARE(x =3D=3D indexes_from_1, alternating_mask); + COMPARE(x =3D=3D indexes_from_0, !alternating_mask); + where(!alternating_mask, x).copy_from(mem, overaligned); + COMPARE(x =3D=3D indexes_from_0, !alternating_mask); + COMPARE(x =3D=3D indexes_from_1, alternating_mask); + + x =3D where(alternating_mask, V()).copy_from(&mem[V::size()], stride_a= ligned); + COMPARE(x =3D=3D indexes_from_size, alternating_mask); + COMPARE(x =3D=3D 0, !alternating_mask); + + x =3D where(!alternating_mask, V()).copy_from(&mem[1], element_aligned= ); + COMPARE(x =3D=3D indexes_from_1, !alternating_mask); + COMPARE(x =3D=3D 0, alternating_mask); + + // stores + auto&& init_mem =3D [&mem](U init) { + for (auto i =3D mem_size; i; --i) + { + mem[i - 1] =3D init; + } + }; + init_mem(-1); + x =3D indexes_from_1; + x.copy_to(&mem[V::size()], stride_aligned); + std::size_t i =3D 0; + for (; i < V::size(); ++i) + { + COMPARE(mem[i], U(-1)) << "i: " << i; + } + for (; i < 2 * V::size(); ++i) + { + COMPARE(mem[i], U(i - V::size() + 1)) << "i: " << i; + } + for (; i < 3 * V::size(); ++i) + { + COMPARE(mem[i], U(-1)) << "i: " << i; + } + + init_mem(-1); + x.copy_to(&mem[1], element_aligned); + COMPARE(mem[0], U(-1)); + for (i =3D 1; i <=3D V::size(); ++i) + { + COMPARE(mem[i], U(i)); + } + for (; i < 3 * V::size(); ++i) + { + COMPARE(mem[i], U(-1)); + } + + init_mem(-1); + x.copy_to(mem, vector_aligned); + for (i =3D 0; i < V::size(); ++i) + { + COMPARE(mem[i], U(i + 1)); + } + for (; i < 3 * V::size(); ++i) + { + COMPARE(mem[i], U(-1)); + } + + init_mem(-1); + where(alternating_mask, indexes_from_0) + .copy_to(&mem[V::size()], stride_aligned); + for (i =3D 0; i < V::size() + 1; ++i) + { + COMPARE(mem[i], U(-1)); + } + for (; i < 2 * V::size(); i +=3D 2) + { + COMPARE(mem[i], U(i - V::size())); + } + for (i =3D V::size() + 2; i < 2 * V::size(); i +=3D 2) + { + COMPARE(mem[i], U(-1)); + } + for (; i < 3 * V::size(); ++i) + { + COMPARE(mem[i], U(-1)); + } + } + +template + void + test() + { + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + load_store(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc new file mode 100644 index 00000000000..7578f1a8561 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc @@ -0,0 +1,66 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/mathreference.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + + using T =3D typename V::value_type; + constexpr T nan =3D std::__quiet_NaN_v; + constexpr T inf =3D std::__infinity_v; + constexpr T denorm_min =3D std::__denorm_min_v; + constexpr T norm_min =3D std::__norm_min_v; + constexpr T min =3D std::__finite_min_v; + constexpr T max =3D std::__finite_max_v; + test_values({1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 3, + 5, + 7, + 15, + 17, + 31, + 33, + 63, + 65, +#ifdef __STDC_IEC_559__ + nan, + inf, + -inf, + denorm_min, + -denorm_min, + norm_min / 3, + -norm_min / 3, + -T(), + -norm_min, + min, + T(), +#endif + norm_min, + max}, + {10000, +#ifdef __STDC_IEC_559__ + min / 2, +#else + norm_min, +#endif + max / 2}, + MAKE_TESTER(log), MAKE_TESTER(log10), MAKE_TESTER(log1p), + MAKE_TESTER(log2), MAKE_TESTER(logb)); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.= cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc new file mode 100644 index 00000000000..6fbadc67af7 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc @@ -0,0 +1,50 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +template + void + test() + { + using M =3D typename V::mask_type; + static_assert(std::is_convertible::value, + "A smart_reference must be convertible to bool."); + static_assert( + std::is_same() + =3D=3D true)>::value, + "A smart_reference must be comparable against bool."); + static_assert( + vir::test::sfinae_is_callable( + [](auto&& a, auto&& b) -> decltype(std::declval() + =3D=3D std::declval()) { + return {}; + }), + "A smart_reference must be comparable against bool."); + VERIFY(std::experimental::is_simd_mask_v); + + { + M x; // uninitialized + x =3D M{}; // default broadcasts 0 + COMPARE(x, M(false)); + COMPARE(x, M()); + COMPARE(x, M{}); + x =3D M(); // default broadcasts 0 + COMPARE(x, M(false)); + COMPARE(x, M()); + COMPARE(x, M{}); + x =3D x; + for (std::size_t i =3D 0; i < M::size(); ++i) + { + COMPARE(x[i], false); + } + } + + M x(true); + M y(false); + for (std::size_t i =3D 0; i < M::size(); ++i) + { + COMPARE(x[i], true); + COMPARE(y[i], false); + } + y =3D M(true); + COMPARE(x, y); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversion= s.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc new file mode 100644 index 00000000000..0248cd4cb47 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc @@ -0,0 +1,96 @@ +#include "bits/verify.h" + +namespace stdx =3D std::experimental; + +template + void + conversions() + { + using ToV =3D typename To::simd_type; + + using stdx::simd_cast; + using stdx::static_simd_cast; + using stdx::__proposed::resizing_simd_cast; + + auto x =3D resizing_simd_cast(From()); + COMPARE(typeid(x), typeid(To)); + COMPARE(x, To()); + + x =3D resizing_simd_cast(From(true)); + const To ref =3D ToV([](auto i) { return i; }) < int(From::size()); + COMPARE(x, ref) << "converted from: " << From(true); + + const ullong all_bits =3D ~ullong() >> (64 - From::size()); + for (ullong bit_pos =3D 1; bit_pos /*until overflow*/; bit_pos *=3D 2) + { + for (ullong bits : {bit_pos & all_bits, ~bit_pos & all_bits}) + { + const auto from =3D From::__from_bitset(bits); + const auto to =3D resizing_simd_cast(from); + COMPARE(to, To::__from_bitset(bits)) + << "\nfrom: " << from << "\nbits: " << std::hex << bits << std::dec; + for (std::size_t i =3D 0; i < To::size(); ++i) + { + COMPARE(to[i], (bits >> i) & 1) + << "\nfrom: " << from << "\nto: " << to + << "\nbits: " << std::hex << bits << std::dec << "\ni: " << i; + } + } + } + } + +template + struct rebind_or_max_fixed + { + using type =3D stdx::rebind_simd_t< + T, stdx::resize_simd_t, V>>; + }; + +template + struct rebind_or_max_fixed>> + { + using type =3D stdx::rebind_simd_t; + }; + +template + void + apply_abis() + { + using M0 =3D typename rebind_or_max_fixed::type; + using M1 =3D stdx::native_simd_mask; + using M2 =3D stdx::simd_mask; + using M3 =3D stdx::simd_mask; + + using std::is_same_v; + conversions(); + if constexpr (!is_same_v) + conversions(); + if constexpr (!is_same_v && !is_same_v) + conversions(); + if constexpr (!is_same_v && !is_same_v && !is_same_v) + conversions(); + } + +template + void + test() + { + using M =3D typename V::mask_type; + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + apply_abis(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_c= vt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc new file mode 100644 index 00000000000..3fa8dab5799 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc @@ -0,0 +1,85 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +template + constexpr bool assign_should_work + =3D std::is_same::value + || (std::is_same>::value + && std::is_same::value= ); + +template + constexpr bool assign_should_not_work =3D !assign_should_work; + +template + std::enable_if_t> + implicit_conversions_test() + { + L x =3D R(true); + COMPARE(x, L(true)); + x =3D R(false); + COMPARE(x, L(false)); + R y(false); + y[0] =3D true; + x =3D y; + L ref(false); + ref[0] =3D true; + COMPARE(x, ref); + } + +template + std::enable_if_t> + implicit_conversions_test() + { + VERIFY((is_substitution_failure) ); + } + +template + void + test() + { + using M =3D typename V::mask_type; + using std::experimental::fixed_size_simd_mask; + using std::experimental::native_simd_mask; + using std::experimental::simd_mask; + + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>= (); + implicit_conversions_test>(= ); + implicit_conversions_test>(); + implicit_conversions_test>(= ); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(= ); + implicit_conversions_test>(); + implicit_conversions_test>(); + implicit_conversions_test>(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.= cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc new file mode 100644 index 00000000000..5e3fd6d867c =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc @@ -0,0 +1,144 @@ +#include "bits/verify.h" + +// simd_mask generator functions +template + M + make_mask(const std::initializer_list& init) + { + std::size_t i =3D 0; + M r =3D {}; + for (;;) + { + for (bool x : init) + { + r[i] =3D x; + if (++i =3D=3D M::size()) + { + return r; + } + } + } + } + +template + M + make_alternating_mask() + { + return make_mask({false, true}); + } + +template + void + test() + { + using M =3D typename V::mask_type; + // loads + constexpr size_t alignment =3D 2 * std::experimental::memory_alignment= _v; + alignas(alignment) bool mem[3 * M::size()]; + std::memset(mem, 0, sizeof(mem)); + for (std::size_t i =3D 1; i < sizeof(mem) / sizeof(*mem); i +=3D 2) + { + COMPARE(mem[i - 1], false); + mem[i] =3D true; + } + using std::experimental::element_aligned; + using std::experimental::vector_aligned; + constexpr size_t stride_alignment + =3D M::size() & 1 + ? 1 + : M::size() & 2 + ? 2 + : M::size() & 4 + ? 4 + : M::size() & 8 + ? 8 + : M::size() & 16 + ? 16 + : M::size() & 32 + ? 32 + : M::size() & 64 + ? 64 + : M::size() & 128 ? 128 + : M::size() & 256 ? 256 : 512; + using stride_aligned_t =3D std::conditional_t< + M::size() =3D=3D stride_alignment, decltype(vector_aligned), + std::experimental::overaligned_tag>; + constexpr stride_aligned_t stride_aligned =3D {}; + constexpr auto overaligned =3D std::experimental::overaligned; + + const M alternating_mask =3D make_alternating_mask(); + + M x(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 =3D=3D 1 ? !alternating_mask : alternating_ma= sk) + << x.__to_bitset() + << ", alternating_mask: " << alternating_mask.__to_bitset(); + x =3D {&mem[1], element_aligned}; + COMPARE(x, !alternating_mask); + x =3D M{mem, overaligned}; + COMPARE(x, alternating_mask); + + x.copy_from(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 =3D=3D 1 ? !alternating_mask : alternating_ma= sk); + x.copy_from(&mem[1], element_aligned); + COMPARE(x, !alternating_mask); + x.copy_from(mem, vector_aligned); + COMPARE(x, alternating_mask); + + x =3D !alternating_mask; + where(alternating_mask, x).copy_from(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 =3D=3D 1 ? !alternating_mask : M{true}); + x =3D M(true); // 1= 111 + where(alternating_mask, x).copy_from(&mem[1], element_aligned); // loa= d .0.0 + COMPARE(x, !alternating_mask); // 1010 + where(alternating_mask, x).copy_from(mem, overaligned); // loa= d .1.1 + COMPARE(x, M{true}); // 1111 + + // stores + memset(mem, 0, sizeof(mem)); + x =3D M(true); + x.copy_to(&mem[M::size()], stride_aligned); + std::size_t i =3D 0; + for (; i < M::size(); ++i) + { + COMPARE(mem[i], false); + } + for (; i < 2 * M::size(); ++i) + { + COMPARE(mem[i], true) << "i: " << i << ", x: " << x; + } + for (; i < 3 * M::size(); ++i) + { + COMPARE(mem[i], false); + } + memset(mem, 0, sizeof(mem)); + x.copy_to(&mem[1], element_aligned); + COMPARE(mem[0], false); + for (i =3D 1; i <=3D M::size(); ++i) + { + COMPARE(mem[i], true); + } + for (; i < 3 * M::size(); ++i) + { + COMPARE(mem[i], false); + } + memset(mem, 0, sizeof(mem)); + alternating_mask.copy_to(mem, overaligned); + for (i =3D 0; i < M::size(); ++i) + { + COMPARE(mem[i], (i & 1) =3D=3D 1); + } + for (; i < 3 * M::size(); ++i) + { + COMPARE(mem[i], false); + } + x.copy_to(mem, vector_aligned); + where(alternating_mask, !x).copy_to(mem, overaligned); + for (i =3D 0; i < M::size(); ++i) + { + COMPARE(mem[i], i % 2 =3D=3D 0); + } + for (; i < 3 * M::size(); ++i) + { + COMPARE(mem[i], false); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_c= vt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc new file mode 100644 index 00000000000..cb968d02785 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc @@ -0,0 +1,94 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +using schar =3D signed char; +using uchar =3D unsigned char; +using ushort =3D unsigned short; +using uint =3D unsigned int; +using ulong =3D unsigned long; +using llong =3D long long; +using ullong =3D unsigned long long; +using ldouble =3D long double; +using wchar =3D wchar_t; +using char16 =3D char16_t; +using char32 =3D char32_t; + +template + constexpr bool + bit_and_is_illformed() + { + return is_substitution_failure>; + } + +template + void + test_binary_op_cvt() + { + COMPARE((bit_and_is_illformed()), !(std::is_same_v) ); + } + +template + void + test() + { + using M =3D typename V::mask_type; + // binary ops without conversions work + COMPARE(typeid(M() & M()), typeid(M)); + + // nothing else works: no implicit conv. or ambiguous + using std::experimental::fixed_size_simd_mask; + using std::experimental::native_simd_mask; + using std::experimental::simd_mask; + test_binary_op_cvt(); + + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + test_binary_op_cvt>(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.= cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc new file mode 100644 index 00000000000..f729adc55bf =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc @@ -0,0 +1,40 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +template + void + test() + { + using M =3D typename V::mask_type; + { // compares + M x(true), y(false); + VERIFY(all_of(x =3D=3D x)); + VERIFY(all_of(x !=3D y)); + VERIFY(all_of(y !=3D x)); + VERIFY(!all_of(x !=3D x)); + VERIFY(!all_of(x =3D=3D y)); + VERIFY(!all_of(y =3D=3D x)); + } + { // subscripting + M x(true); + for (std::size_t i =3D 0; i < M::size(); ++i) + { + COMPARE(x[i], true) << "\nx: " << x << ", i: " << i; + x[i] =3D !x[i]; + } + COMPARE(x, M{false}); + for (std::size_t i =3D 0; i < M::size(); ++i) + { + COMPARE(x[i], false) << "\nx: " << x << ", i: " << i; + x[i] =3D !x[i]; + } + COMPARE(x, M{true}); + } + { // negation + M x(false); + M y =3D !x; + COMPARE(y, M{true}); + COMPARE(!y, x); + } + } + diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions= =2Ecc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc new file mode 100644 index 00000000000..99912aad9c0 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc @@ -0,0 +1,209 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +// simd_mask generator functions +template + M + make_mask(const std::initializer_list& init) + { + std::size_t i =3D 0; + M r =3D {}; + for (;;) + { + for (bool x : init) + { + r[i] =3D x; + if (++i =3D=3D M::size()) + { + return r; + } + } + } + } + +template + M + make_alternating_mask() + { + return make_mask({false, true}); + } + +template + void + test() + { + using M =3D typename V::mask_type; + const M alternating_mask =3D make_alternating_mask(); + COMPARE(alternating_mask[0], false); // assumption below + auto&& gen =3D make_mask; + + // all_of + VERIFY(all_of(M{true})); + VERIFY(!all_of(alternating_mask)); + VERIFY(!all_of(M{false})); + using std::experimental::all_of; + VERIFY(all_of(true)); + VERIFY(!all_of(false)); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; })); + + // any_of + VERIFY(any_of(M{true})); + COMPARE(any_of(alternating_mask), M::size() > 1); + VERIFY(!any_of(M{false})); + using std::experimental::any_of; + VERIFY(any_of(true)); + VERIFY(!any_of(false)); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; })); + + // none_of + VERIFY(!none_of(M{true})); + COMPARE(none_of(alternating_mask), M::size() =3D=3D 1); + VERIFY(none_of(M{false})); + using std::experimental::none_of; + VERIFY(!none_of(true)); + VERIFY(none_of(false)); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; })); + + // some_of + VERIFY(!some_of(M{true})); + VERIFY(!some_of(M{false})); + if (M::size() > 1) + { + VERIFY(some_of(gen({true, false}))); + VERIFY(some_of(gen({false, true}))); + if (M::size() > 3) + { + VERIFY(some_of(gen({0, 0, 0, 1}))); + } + } + using std::experimental::some_of; + VERIFY(!some_of(true)); + VERIFY(!some_of(false)); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; })); + + // popcount + COMPARE(popcount(M{true}), int(M::size())); + COMPARE(popcount(alternating_mask), int(M::size()) / 2); + COMPARE(popcount(M{false}), 0); + COMPARE(popcount(gen({0, 0, 1})), int(M::size()) / 3); + COMPARE(popcount(gen({0, 0, 0, 1})), int(M::size()) / 4); + COMPARE(popcount(gen({0, 0, 0, 0, 1})), int(M::size()) / 5); + COMPARE(std::experimental::popcount(true), 1); + COMPARE(std::experimental::popcount(false), 0); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; })); + + // find_first_set + { + M x(false); + for (int i =3D int(M::size() / 2 - 1); i >=3D 0; --i) + { + x[i] =3D true; + COMPARE(find_first_set(x), i) << x; + } + x =3D M(false); + for (int i =3D int(M::size() - 1); i >=3D 0; --i) + { + x[i] =3D true; + COMPARE(find_first_set(x), i) << x; + } + } + COMPARE(find_first_set(M{true}), 0); + if (M::size() > 1) + { + COMPARE(find_first_set(gen({0, 1})), 1); + } + if (M::size() > 2) + { + COMPARE(find_first_set(gen({0, 0, 1})), 2); + } + COMPARE(std::experimental::find_first_set(true), 0); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_first_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_first_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_first_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_first_set(x)) { + return {}; + })); + + // find_last_set + { + M x(false); + for (int i =3D 0; i < int(M::size()); ++i) + { + x[i] =3D true; + COMPARE(find_last_set(x), i) << x; + } + } + COMPARE(find_last_set(M{true}), int(M::size()) - 1); + if (M::size() > 1) + { + COMPARE(find_last_set(gen({1, 0})), + int(M::size()) - 2 + int(M::size() & 1)); + } + if (M::size() > 3 && (M::size() & 3) =3D=3D 0) + { + COMPARE(find_last_set(gen({1, 0, 0, 0})), + int(M::size()) - 4 - int(M::size() & 3)); + } + COMPARE(std::experimental::find_last_set(true), 0); + VERIFY(sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_last_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_last_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_last_set(x)) { + return {}; + })); + VERIFY(!sfinae_is_callable( + [](auto x) -> decltype(std::experimental::find_last_set(x)) { + return {}; + })); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc new file mode 100644 index 00000000000..748fd1d3866 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc @@ -0,0 +1,90 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T =3D typename V::value_type; + constexpr T inf =3D std::__infinity_v; + constexpr T nan =3D std::__quiet_NaN_v; + constexpr T denorm_min =3D std::__denorm_min_v; + constexpr T norm_min =3D std::__norm_min_v; + constexpr T max =3D std::__finite_max_v; +#if defined __LONG_DOUBLE_IBM128__ + // On POWER with IBM128 long double, 1+eps and 2-eps is not a constant + // expression. Until this is fixed, just use const instead of constexp= r. + // (error: '(1.0e+0l + 4.94065645841246544176568792868221e-324l)' is n= ot a + // constant expression) + const T after_one =3D 1 + std::__epsilon_v; + const T before_one =3D (2 - std::__epsilon_v) / 2; +#else + constexpr T after_one =3D 1 + std::__epsilon_v; + constexpr T before_one =3D (2 - std::__epsilon_v) / 2; +#endif + const std::initializer_list + input_values =3D {+0., + 0.5, + -0.5, + before_one, + -before_one, + after_one, + -after_one, + 1.5, + -1.5, + 2 * before_one, + -2 * before_one, + 2 * after_one, + -2 * after_one, + 2.5, + -2.5, + 0x1.fffffffffffffp52, + -0x1.fffffffffffffp52, + 0x1.ffffffffffffep52, + -0x1.ffffffffffffep52, + 0x1.ffffffffffffdp52, + -0x1.ffffffffffffdp52, + 0x1.fffffep21, + -0x1.fffffep21, + 0x1.fffffcp21, + -0x1.fffffcp21, + 0x1.fffffep22, + -0x1.fffffep22, + 0x1.fffffcp22, + -0x1.fffffcp22, + 0x1.fffffep23, + -0x1.fffffep23, + 0x1.fffffcp23, + -0x1.fffffcp23, + 0x1.8p23, + -0x1.8p23, + inf, + -inf, + -0., + nan, + denorm_min, + norm_min / 3, + norm_min, + max}; + test_values(input_values, {10000}, MAKE_TESTER(erf), MAKE_TESTER(er= fc), + MAKE_TESTER(tgamma), MAKE_TESTER(lgamma), MAKE_TESTER(ceil), + MAKE_TESTER(floor), MAKE_TESTER(trunc), MAKE_TESTER(round), + MAKE_TESTER(lround), MAKE_TESTER(llround), + MAKE_TESTER(nearbyint), MAKE_TESTER(rint), MAKE_TESTER(lrint), + MAKE_TESTER(llrint), MAKE_TESTER(ilogb)); + + // sqrt(x) on x87 is precise in 80 bits, but the subsequent rounding c= an be + // wrong (up to 1 ULP) +#if __FLT_EVAL_METHOD__ =3D=3D 1 + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(0); +#elif __FLT_EVAL_METHOD__ =3D=3D 2 + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); +#endif + test_values(input_values, {10000}, MAKE_TESTER(sqrt)); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc new file mode 100644 index 00000000000..ef425fa4221 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc @@ -0,0 +1,62 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + using T =3D typename V::value_type; + + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + test_values_2arg( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, std::__infinity_v, -std::__infinity_v, -0., + std::__denorm_min_v, std::__norm_min_v / 3, +#endif + +0., std::__norm_min_v, 1., 2., std::__finite_max_v / 5, + std::__finite_max_v / 3, std::__finite_max_v / 2, +#ifdef __FAST_MATH__ + // fast-math hypot is imprecise for the max exponent + }, + {100000, std::__finite_max_v / 2}, +#else + std::__finite_max_v}, + {100000}, +#endif + MAKE_TESTER(hypot)); +#if !__FINITE_MATH_ONLY__ + COMPARE(hypot(V(std::__finite_max_v), V(std::__finite_max_v)), + V(std::__infinity_v)); +#endif + COMPARE(hypot(V(std::__norm_min_v), V(std::__norm_min_v)), + V(std::__norm_min_v * std::sqrt(T(2)))); + VERIFY((sfinae_is_callable( + [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; }))); + VERIFY((sfinae_is_callable( + [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; }))); + VERIFY((sfinae_is_callable( + [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; }))); + + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + test_values_2arg( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, std::__infinity_v, -std::__infinity_v, + std::__denorm_min_v, std::__norm_min_v / 3, -0., +#endif + +0., std::__norm_min_v, std::__finite_max_v}, + {10000}, MAKE_TESTER(pow), MAKE_TESTER(fmod), MAKE_TESTER(remainder), + MAKE_TESTER_NOFPEXCEPT(copysign), + MAKE_TESTER(nextafter), // MAKE_TESTER(nexttoward), + MAKE_TESTER(fdim), MAKE_TESTER(fmax), MAKE_TESTER(fmin), + MAKE_TESTER_NOFPEXCEPT(isgreater), MAKE_TESTER_NOFPEXCEPT(isgreatere= qual), + MAKE_TESTER_NOFPEXCEPT(isless), MAKE_TESTER_NOFPEXCEPT(islessequal), + MAKE_TESTER_NOFPEXCEPT(islessgreater), MAKE_TESTER_NOFPEXCEPT(isunor= dered)); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc= b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc new file mode 100644 index 00000000000..1c73e299981 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc @@ -0,0 +1,1055 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" + +// type with sizeof(char) but different signedness +using xchar =3D std::conditional_t, schar, uchar>; + +using vschar =3D std::experimental::native_simd; +using vuchar =3D std::experimental::native_simd; +using vshort =3D std::experimental::native_simd; +using vushort =3D std::experimental::native_simd; +using vint =3D std::experimental::native_simd; +using vuint =3D std::experimental::native_simd; +using vlong =3D std::experimental::native_simd; +using vulong =3D std::experimental::native_simd; +using vllong =3D std::experimental::native_simd; +using vullong =3D std::experimental::native_simd; +using vfloat =3D std::experimental::native_simd; +using vdouble =3D std::experimental::native_simd; +using vldouble =3D std::experimental::native_simd; +using vchar =3D std::experimental::native_simd; +using vxchar =3D std::experimental::native_simd; + +template + using vi8 =3D std::experimental::fixed_size_simd; +template + using vi16 =3D std::experimental::fixed_size_simd; +template + using vf32 =3D std::experimental::fixed_size_simd; +template + using vi32 =3D std::experimental::fixed_size_simd; +template + using vf64 =3D std::experimental::fixed_size_simd; +template + using vi64 =3D std::experimental::fixed_size_simd; +template + using vl =3D typename std::conditional, + vi32>::type; + +template + void + binary_op_return_type() + { + using namespace vir::test; + static_assert(std::is_same::value, ""); + using AC =3D std::add_const_t; + using BC =3D std::add_const_t; + COMPARE(typeid(A() + B()), typeid(Expected)); + COMPARE(typeid(B() + A()), typeid(Expected)); + COMPARE(typeid(AC() + BC()), typeid(Expected)); + COMPARE(typeid(BC() + AC()), typeid(Expected)); + } + +template + void + test() + { + using T =3D typename V::value_type; + namespace simd_abi =3D std::experimental::simd_abi; + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + + if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + + binary_op_return_type, schar>(); + binary_op_return_type, uchar>(); + binary_op_return_type, short>(); + binary_op_return_type, ushort>(); + binary_op_return_type, int>(); + binary_op_return_type, float>(); + + binary_op_return_type, vf32>(); + binary_op_return_type, vf32>(); + binary_op_return_type, vf32>(); + binary_op_return_type, vf32>(); + binary_op_return_type, vf32>(); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + + VERIFY((is_substitution_failure, vfloat>)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vf32>)); + VERIFY((is_substitution_failure, vf32>)); + VERIFY((is_substitution_failure, vf32>)); + VERIFY((is_substitution_failure, vf32>)); + VERIFY((is_substitution_failure, vf32>)); + VERIFY((is_substitution_failure, vf32>)); + + VERIFY((is_substitution_failure>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + + binary_op_return_type, schar>(); + binary_op_return_type, uchar>(); + binary_op_return_type, short>(); + binary_op_return_type, ushort>(); + binary_op_return_type, uint>(); + binary_op_return_type, int, vf64>(); + binary_op_return_type, float, vf64>(); + binary_op_return_type, double, vf64>(); + binary_op_return_type, vf64, vf64>(); + binary_op_return_type, schar>(); + binary_op_return_type, uchar>(); + binary_op_return_type, short>(); + binary_op_return_type, ushort>(); + binary_op_return_type, uint>(); + binary_op_return_type, int, vf32>(); + binary_op_return_type, float, vf32>(); + binary_op_return_type, double, vf32>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + + VERIFY((is_substitution_failure, vdouble>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, vf64>)); + VERIFY((is_substitution_failure, vf64>)); + + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, vf64>)); + VERIFY((is_substitution_failure, vf64>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + } + else + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, long>(); + binary_op_return_type, ulong>(); + binary_op_return_type, vf64>(); + binary_op_return_type, vf64>(); + binary_op_return_type, long>(); + binary_op_return_type, ulong>(); + } + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + + binary_op_return_type, schar>(); + binary_op_return_type, uchar>(); + binary_op_return_type, short>(); + binary_op_return_type, ushort>(); + binary_op_return_type, int>(); + binary_op_return_type, uint>(); + binary_op_return_type, long>(); + binary_op_return_type, ulong>(); + binary_op_return_type, float>(); + binary_op_return_type, double>(); + binary_op_return_type, vf64>(); + + using std::experimental::simd; + using A =3D simd_abi::fixed_size; + binary_op_return_type, schar>(); + binary_op_return_type, uchar>(); + binary_op_return_type, short>(); + binary_op_return_type, ushort>(); + binary_op_return_type, int>(); + binary_op_return_type, uint>(); + binary_op_return_type, long>(); + binary_op_return_type, ulong>(); + binary_op_return_type, float>(); + binary_op_return_type, double>(); + + if constexpr (sizeof(ldouble) =3D=3D sizeof(double)) + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + } + else + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, llong>(); + binary_op_return_type, ullong>(); + binary_op_return_type, llong>(); + binary_op_return_type, ullong>(); + } + + VERIFY((is_substitution_failure, vldouble>)); + COMPARE((is_substitution_failure, vldouble>), + (!std::is_same::value)); + } + else if constexpr (std::is_same_v) + { + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, vi32>)); + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, uint>(); + binary_op_return_type, llong>(); + binary_op_return_type, uint>(); + binary_op_return_type, llong>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi64>)); + } + else + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi32>(); + binary_op_return_type, vi64>(); + } + + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + + binary_op_return_type, schar, vi32>(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, short, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, long, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, schar, vi64>(); + binary_op_return_type, uchar, vi64>(); + binary_op_return_type, short, vi64>(); + binary_op_return_type, ushort, vi64>(); + binary_op_return_type, int, vi64>(); + binary_op_return_type, long, vi64>(); + binary_op_return_type, vi64, vi64>(); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vlong>)); + VERIFY((is_substitution_failure, vulong>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + + binary_op_return_type, vi32>(); + binary_op_return_type, vi64>(); + } + else if constexpr (std::is_same_v) + { + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + binary_op_return_type(); + binary_op_return_type, ullong, vi32>(); + binary_op_return_type, ullong, vi64>(); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + } + else + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, ullong>)); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + } + + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, uint, vi32>(); + binary_op_return_type, ulong, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, uchar, vi64>(); + binary_op_return_type, ushort, vi64>(); + binary_op_return_type, int, vi64>(); + binary_op_return_type, uint, vi64>(); + binary_op_return_type, ulong, vi64>(); + binary_op_return_type, vi64, vi64>(); + + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vlong>)); + VERIFY((is_substitution_failure, vulong>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, schar, vi32>(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, short, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, uint, vi32>(); + binary_op_return_type, long, vi32>(); + binary_op_return_type, llong, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, schar, vi64>(); + binary_op_return_type, uchar, vi64>(); + binary_op_return_type, short, vi64>(); + binary_op_return_type, ushort, vi64>(); + binary_op_return_type, int, vi64>(); + binary_op_return_type, uint, vi64>(); + binary_op_return_type, long, vi64>(); + binary_op_return_type, llong, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure)); + } + else + { + binary_op_return_type, vi32>(); + binary_op_return_type, ulong>(); + binary_op_return_type, ulong>(); + binary_op_return_type(); + } + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vllong>)); + VERIFY((is_substitution_failure, vullong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + binary_op_return_type, vi64>(); + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + VERIFY((is_substitution_failure, vi64>)); + } + else + { + binary_op_return_type, vi64>(); + } + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, uint, vi32>(); + binary_op_return_type, ulong, vi32>(); + binary_op_return_type, ullong, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, uchar, vi64>(); + binary_op_return_type, ushort, vi64>(); + binary_op_return_type, int, vi64>(); + binary_op_return_type, uint, vi64>(); + binary_op_return_type, ulong, vi64>(); + binary_op_return_type, ullong, vi64>(); + binary_op_return_type, vi64, vi64>(); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + binary_op_return_type, vi32>(); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, vllong>)); + VERIFY((is_substitution_failure, vullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + binary_op_return_type, vi64>(); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + VERIFY((is_substitution_failure, vi64>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, schar, vi32>(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, short, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + + // order is important for MSVC. This compiler is just crazy: It considers + // operators from unrelated simd template instantiations as candidates - + // but only after they have been tested. So e.g. vi32 + llong will + // produce a vi32 if a vi32 operator test is done before the + // vi32 + llong test. + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vint>)); + VERIFY((is_substitution_failure, vuint>)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + + binary_op_return_type, vi32>(); + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, long>)); + } + else + { + binary_op_return_type(); + binary_op_return_type, long>(); + } + } + else if constexpr (std::is_same_v) + { + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, vi32>)); + + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, uchar, vi32>(); + binary_op_return_type, ushort, vi32>(); + binary_op_return_type, int, vi32>(); + binary_op_return_type, uint, vi32>(); + binary_op_return_type, vi32, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + binary_op_return_type, vi32>(); + + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, vint>)); + VERIFY((is_substitution_failure, vuint>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + VERIFY((is_substitution_failure, vi32>)); + + binary_op_return_type, vi32>(); + if constexpr (sizeof(long) =3D=3D sizeof(llong)) + { + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure, ulong>)); + binary_op_return_type, vi32>(); + } + else + { + binary_op_return_type(); + binary_op_return_type, ulong>(); + VERIFY((is_substitution_failure, vi32>)); + } + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, schar, vi16>(); + binary_op_return_type, uchar, vi16>(); + binary_op_return_type, short, vi16>(); + binary_op_return_type, int, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vshort>)); + VERIFY((is_substitution_failure, vushort>)); + VERIFY((is_substitution_failure, ushort>)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, vi16>)); + VERIFY((is_substitution_failure, vi16>)); + VERIFY((is_substitution_failure, vi16>)); + VERIFY((is_substitution_failure, vi16>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type(); + binary_op_return_type(); + binary_op_return_type, uchar, vi16>(); + binary_op_return_type, ushort, vi16>(); + binary_op_return_type, int, vi16>(); + binary_op_return_type, uint, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + binary_op_return_type, vi16>(); + + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, vshort>)); + VERIFY((is_substitution_failure, vushort>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, vi16>)); + VERIFY((is_substitution_failure, vi16>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type, char, vi8>(); + binary_op_return_type, int, vi8>(); + binary_op_return_type, vi8, vi8>(); + + if constexpr (vi8::size() <=3D simd_abi::max_fixed_size) + { + VERIFY(!(is_substitution_failure, vi8>)); + VERIFY(!(is_substitution_failure, vi8>)); + VERIFY(!(is_substitution_failure, vi8>)); + VERIFY(!(is_substitution_failure, vi8>)); + COMPARE((is_substitution_failure, vi8>), + std::is_signed_v); + COMPARE((is_substitution_failure, vi8>), + std::is_signed_v); + COMPARE((is_substitution_failure, vi8>), + std::is_signed_v); + COMPARE((is_substitution_failure, vi8>), + std::is_signed_v); + if constexpr (std::is_signed_v) + { + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + } + else + { + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + } + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + } + + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + COMPARE((is_substitution_failure), std::is_signed_v); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vchar>)); + VERIFY((is_substitution_failure, vuchar>)); + VERIFY((is_substitution_failure, vschar>)); + VERIFY((is_substitution_failure, xchar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, ushort>)); + COMPARE((is_substitution_failure, uint>), + std::is_signed_v); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + + // conversion between any char types must fail because the dst type's + // integer conversion rank isn't greater (as required by 9.6.4p4.3) + VERIFY((is_substitution_failure, vi8>)); + VERIFY((is_substitution_failure, vi8>)); + } + else if constexpr (std::is_same_v) + { + binary_op_return_type, schar, vi8>(); + binary_op_return_type, int, vi8>(); + binary_op_return_type, vi8, vi8>(); + + if constexpr (vi8::size() <=3D simd_abi::max_fixed_size) + { + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + } + + VERIFY((is_substitution_failure, llong>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, vschar>)); + VERIFY((is_substitution_failure, vuchar>)); + VERIFY((is_substitution_failure, uchar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, ushort>)); + VERIFY((is_substitution_failure, uint>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, vi8>)); + VERIFY((is_substitution_failure, vi8>)); + VERIFY((is_substitution_failure, vi8>)); + VERIFY((is_substitution_failure, vi8>)); + VERIFY((is_substitution_failure, vi8>)); + } + else if constexpr (std::is_same_v) + { + VERIFY((is_substitution_failure, llong>)); + + binary_op_return_type(); + binary_op_return_type, uchar, vi8>(); + binary_op_return_type, int, vi8>(); + binary_op_return_type, uint, vi8>(); + binary_op_return_type, vi8, vi8>(); + + if constexpr (vi8::size() <=3D simd_abi::max_fixed_size) + { + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + binary_op_return_type, vi8>(); + } + + VERIFY((is_substitution_failure, ullong>)); + VERIFY((is_substitution_failure, double>)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure>)); + VERIFY((is_substitution_failure, schar>)); + VERIFY((is_substitution_failure, vschar>)); + VERIFY((is_substitution_failure, vuchar>)); + VERIFY((is_substitution_failure, short>)); + VERIFY((is_substitution_failure, ushort>)); + VERIFY((is_substitution_failure, long>)); + VERIFY((is_substitution_failure, ulong>)); + VERIFY((is_substitution_failure, float>)); + VERIFY((is_substitution_failure, vi8>)); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc b/= libstdc++-v3/testsuite/experimental/simd/tests/operators.cc new file mode 100644 index 00000000000..566c5c994e8 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc @@ -0,0 +1,297 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include "bits/verify.h" +#include "bits/make_vec.h" +#include "bits/test_values.h" + +template + constexpr T + genHalfBits() + { + if constexpr (std::is_floating_point_v) + return 0; + else + return std::__finite_max_v >> (std::__digits_v / 2); + } + +template + void + test() + { + using M =3D typename V::mask_type; + using T =3D typename V::value_type; + constexpr auto min =3D std::__finite_min_v; + constexpr auto norm_min =3D std::__norm_min_v; + constexpr auto max =3D std::__finite_max_v; + { // compares + COMPARE(V(0) =3D=3D make_vec({0, 1}, 0), make_mask({1, 0})); + COMPARE(V(0) =3D=3D make_vec({0, 1, 2}, 0), make_mask({1, 0, 0= })); + COMPARE(V(1) =3D=3D make_vec({0, 1, 2}, 0), make_mask({0, 1, 0= })); + COMPARE(V(2) =3D=3D make_vec({0, 1, 2}, 0), make_mask({0, 0, 1= })); + COMPARE(V(0) < make_vec({0, 1, 2}, 0), make_mask({0, 1, 1})); + + constexpr T half =3D genHalfBits(); + for (T lo_ : {min, T(min + 1), T(-1), T(0), norm_min, T(1), T(half -= 1), + half, T(half + 1), T(max - 1)}) + { + for (T hi_ : {T(min + 1), T(-1), T(0), norm_min, T(1), T(half - 1), + half, T(half + 1), T(max - 1), max}) + { + if (hi_ <=3D lo_) + continue; + + for (std::size_t pos =3D 0; pos < V::size(); ++pos) + { + V lo =3D lo_; + V hi =3D hi_; + lo[pos] =3D 0; // have a different value in the vector in case + hi[pos] =3D 1; // this affects neighbors + COMPARE(hi, hi); + VERIFY(all_of(hi !=3D lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(lo !=3D hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(hi !=3D hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(hi =3D=3D lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(lo =3D=3D hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(lo < hi)) << "hi: " << hi << ", lo: " << lo + << ", lo < hi: " << (lo < hi); + VERIFY(none_of(hi < lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(hi <=3D lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi <=3D hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi > lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(lo > hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi >=3D lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi >=3D hi)) << "hi: " << hi << ", lo: " << lo; + } + } + } + } + { // subscripting + V x =3D max; + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(x[i], max); + x[i] =3D 0; + } + COMPARE(x, V{0}); + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(x[i], T(0)); + x[i] =3D max; + } + COMPARE(x, V{max}); + COMPARE(typeid(x[0] * x[0]), typeid(T() * T())); + COMPARE(typeid(x[0] * T()), typeid(T() * T())); + COMPARE(typeid(T() * x[0]), typeid(T() * T())); + COMPARE(typeid(x * x[0]), typeid(x)); + COMPARE(typeid(x[0] * x), typeid(x)); + + x =3D V([](auto i) -> T { return i; }); + for (std::size_t i =3D 0; i < V::size(); ++i) + { + COMPARE(x[i], T(i)); + } + for (std::size_t i =3D 0; i + 1 < V::size(); i +=3D 2) + { + using std::swap; + swap(x[i], x[i + 1]); + } + for (std::size_t i =3D 0; i + 1 < V::size(); i +=3D 2) + { + COMPARE(x[i], T(i + 1)) << x; + COMPARE(x[i + 1], T(i)) << x; + } + x =3D 1; + V y =3D 0; + COMPARE(x[0], T(1)); + x[0] =3D y[0]; // make sure non-const smart_reference assignment wor= ks + COMPARE(x[0], T(0)); + x =3D 1; + x[0] =3D x[0]; // self-assignment on smart_reference + COMPARE(x[0], T(1)); + + std::experimental::simd + z =3D 2; + x[0] =3D z[0]; + COMPARE(x[0], T(2)); + x =3D 3; + z[0] =3D x[0]; + COMPARE(z[0], T(3)); + + // TODO: check that only value-preserving conversions happen on subs= cript + // assignment + } + { // not + V x =3D 0; + COMPARE(!x, M{true}); + V y =3D 1; + COMPARE(!y, M{false}); + } + + { // unary minus + V x =3D 0; + COMPARE(-x, V(T(-T(0)))); + V y =3D 1; + COMPARE(-y, V(T(-T(1)))); + } + + { // plus + V x =3D 0; + V y =3D 0; + COMPARE(x + y, x); + COMPARE(x =3D x + T(1), V(1)); + COMPARE(x + x, V(2)); + y =3D make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x =3D x + y, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x =3D x + -y, V(1)); + COMPARE(x +=3D y, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x +=3D -y, V(1)); + COMPARE(x, V(1)); + } + + { // minus + V x =3D 1; + V y =3D 0; + COMPARE(x - y, x); + COMPARE(x - T(1), y); + COMPARE(y, x - T(1)); + COMPARE(x - x, y); + y =3D make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x =3D y - x, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(x =3D y - x, V(1)); + COMPARE(y -=3D x, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(y, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(y -=3D y, V(0)); + COMPARE(y, V(0)); + } + + { // multiplies + V x =3D 1; + V y =3D 0; + COMPARE(x * y, y); + COMPARE(x =3D x * T(2), V(2)); + COMPARE(x * x, V(4)); + y =3D make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x =3D x * y, make_vec({2, 4, 6, 8, 10, 12, 14})); + y =3D 2; + // don't test norm_min/2*2 in the following. There's no guarantee, in + // general, that the result isn't flushed to zero (e.g. NEON without + // subnormals) + for (T n : + {T(max - 1), std::is_floating_point_v ? T(norm_min * 3) : min}) + { + x =3D n / 2; + COMPARE(x * y, V(n)); + } + if (std::is_integral::value && std::is_unsigned::value) + { + // test modulo arithmetics + T n =3D max; + x =3D n; + for (T m : {T(2), T(7), T(max / 127), max}) + { + y =3D m; + // if T is of lower rank than int, `n * m` will promote to int + // before executing the multiplication. In this case an overflow + // will be UB (and ubsan will warn about it). The solution is to + // cast to uint in that case. + using U + =3D std::conditional_t<(sizeof(T) < sizeof(int)), unsigned, T>; + COMPARE(x * y, V(T(U(n) * U(m)))); + } + } + x =3D 2; + COMPARE(x *=3D make_vec({1, 2, 3}), make_vec({2, 4, 6})); + COMPARE(x, make_vec({2, 4, 6})); + } + + // divides + constexpr bool is_iec559 =3D __GCC_IEC_559 >=3D 2; + if constexpr (std::is_floating_point_v && !is_iec559) + { // avoid testing subnormals and expect minor deltas for non-IEC559= float + V x =3D 2; + ULP_COMPARE(x / x, V(1), 1); + ULP_COMPARE(T(3) / x, V(T(3) / T(2)), 1); + ULP_COMPARE(x / T(3), V(T(2) / T(3)), 1); + V y =3D make_vec({1, 2, 3, 4, 5, 6, 7}); + ULP_COMPARE(y / x, + make_vec( + {T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)}), + 1); + + test_values({norm_min * 1024, T(1), T(), T(-1), max / 1024, + max / 4.1, max, min}, + [&](V a) { + V b =3D 2; + V ref([&](auto i) { return a[i] / 2; }); + ULP_COMPARE(a / b, ref, 1); + where(a =3D=3D 0, a) =3D 1; + // -freciprocal-math together with flush-to-zero makes + // the following range restriction necessary (i.e. + // 1/|a| must be >=3D min). Intel vrcpps and vrcp14ps + // need some extra slack (use 1.1 instead of 1). + where(abs(a) >=3D T(1.1) / norm_min, a) =3D 1; + ULP_COMPARE(a / a, V(1), 1) << "\na =3D " << a; + ref =3D V([&](auto i) { return 2 / a[i]; }); + ULP_COMPARE(b / a, ref, 1) << "\na =3D " << a; + ULP_COMPARE(b /=3D a, ref, 1); + ULP_COMPARE(b, ref, 1); + }); + } + else + { + V x =3D 2; + COMPARE(x / x, V(1)); + COMPARE(T(3) / x, V(T(3) / T(2))); + COMPARE(x / T(3), V(T(2) / T(3))); + V y =3D make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(y / x, + make_vec({T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)})); + + y =3D make_vec({max, norm_min}); + V ref =3D make_vec({T(max / 2), T(norm_min / 2)}); + COMPARE(y / x, ref); + + y =3D make_vec({norm_min, max}); + ref =3D make_vec({T(norm_min / 2), T(max / 2)}); + COMPARE(y / x, ref); + + y =3D make_vec({max, T(norm_min + 1)}); + COMPARE(y / y, V(1)); + + ref =3D make_vec({T(2 / max), T(2 / (norm_min + 1))}); + COMPARE(x / y, ref); + COMPARE(x /=3D y, ref); + COMPARE(x, ref); + } + + { // increment & decrement + const V from0 =3D make_vec({0, 1, 2, 3}, 4); + V x =3D from0; + COMPARE(x++, from0); + COMPARE(x, from0 + 1); + COMPARE(++x, from0 + 2); + COMPARE(x, from0 + 2); + + COMPARE(x--, from0 + 2); + COMPARE(x, from0 + 1); + COMPARE(--x, from0); + COMPARE(x, from0); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc b= /libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc new file mode 100644 index 00000000000..a663db23a61 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc @@ -0,0 +1,80 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" +#include + +template + void + test() + { + using T =3D typename V::value_type; + COMPARE(reduce(V(1)), T(V::size())); + { + V x =3D 1; + COMPARE(reduce(x, std::multiplies<>()), T(1)); + x[0] =3D 2; + COMPARE(reduce(x, std::multiplies<>()), T(2)); + if constexpr (V::size() > 1) + { + x[V::size() - 1] =3D 3; + COMPARE(reduce(x, std::multiplies<>()), T(6)); + } + } + COMPARE(reduce(V([](int i) { return i & 1; })), T(V::size() / 2)); + COMPARE(reduce(V([](int i) { return i % 3; })), + T(3 * (V::size() / 3) // 0+1+2 for every complete 3 elements in V + + (V::size() % 3) / 2 // 0->0, 1->0, 2->1 adjustment + )); + if ((1 + V::size()) * V::size() / 2 <=3D std::__finite_max_v) + { + COMPARE(reduce(V([](int i) { return i + 1; })), + T((1 + V::size()) * V::size() / 2)); + } + + { + const V y =3D 2; + COMPARE(reduce(y), T(2 * V::size())); + COMPARE(reduce(where(y > 2, y)), T(0)); + COMPARE(reduce(where(y =3D=3D 2, y)), T(2 * V::size())); + } + + { + const V z([](T i) { return i + 1; }); + COMPARE(std::experimental::reduce(z, + [](auto a, auto b) { + using std::min; + return min(a, b); + }), + T(1)) + << "z: " << z; + COMPARE(std::experimental::reduce(z, + [](auto a, auto b) { + using std::max; + return max(a, b); + }), + T(V::size())) + << "z: " << z; + COMPARE(std::experimental::reduce(where(z > 1, z), 117, + [](auto a, auto b) { + using std::min; + return min(a, b); + }), + T(V::size() =3D=3D 1 ? 117 : 2)) + << "z: " << z; + } + + test_values({}, {1000}, [](V x) { + // avoid over-/underflow on signed integers: + if constexpr (std::is_signed_v && std::is_integral_v) + x /=3D int(V::size()); + // The error in the following could be huge if catastrophic + // cancellation occurs. (e.g. `a-a+b+b` vs. `a+b+b-a`). + // Avoid catastrophic cancellation for floating point: + if constexpr (std::is_floating_point_v) + x =3D abs(x); + T acc =3D x[0]; + for (size_t i =3D 1; i < V::size(); ++i) + acc +=3D x[i]; + ULP_COMPARE(reduce(x), acc, V::size() / 2).on_failure("x =3D ", x); + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc b/libs= tdc++-v3/testsuite/experimental/simd/tests/remqo.cc new file mode 100644 index 00000000000..87eb21ef098 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc @@ -0,0 +1,53 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T =3D typename V::value_type; + test_values_2arg( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, std::__infinity_v, -std::__infinity_v, + std::__denorm_min_v, std::__norm_min_v / 3, -0., +#endif + +0., std::__norm_min_v, std::__finite_max_v}, + {10000}, [](V a, V b) { + +#ifndef __STDC_IEC_559__ + // without __STDC_IEC_559__, remquo(a, 0) is unspecified + where(b =3D=3D 0, b) =3D 1; +#endif + using IV =3D std::experimental::fixed_size_simd; + IV quo =3D {}; + const V totest =3D remquo(a, b, &quo); + auto&& expected + =3D [&](const auto& v, const auto& w) -> std::pair { + std::pair tmp =3D {}; + using std::remquo; + for (std::size_t i =3D 0; i < V::size(); ++i) + { + int tmp2; + tmp.first[i] =3D remquo(v[i], w[i], &tmp2); + tmp.second[i] =3D tmp2; + } + return tmp; + }; + const auto expect1 =3D expected(a, b); + COMPARE(isnan(totest), isnan(expect1.first)) + << "remquo(" << a << ", " << b << ", quo) =3D " << totest + << " !=3D " << expect1.first; + const V clean_a =3D iif(isnan(totest), 0, a); + const V clean_b =3D iif(isnan(totest), 1, b); + const auto expect2 =3D expected(clean_a, clean_b); + COMPARE(remquo(clean_a, clean_b, &quo), expect2.first) + << "\nclean_a/b =3D " << clean_a << ", " << clean_b; + COMPARE(quo, expect2.second); + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc b/libst= dc++-v3/testsuite/experimental/simd/tests/simd.cc new file mode 100644 index 00000000000..0744be5e191 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc @@ -0,0 +1,29 @@ +#include "bits/verify.h" + +template + void + test() + { + using T =3D typename V::value_type; + + // V must store V::size() values of type T giving us the lower bound o= n the + // sizeof + VERIFY(sizeof(V) >=3D sizeof(T) * V::size()); + + // For fixed_size, V should not pad more than to the next-power-of-2 of + // sizeof(T) * V::size() (for ABI stability of V), giving us the upper= bound + // on the sizeof. For non-fixed_size we give the implementation a bit = more + // slack to trade space vs. efficiency. + auto n =3D sizeof(T) * V::size(); + if (n & (n - 1)) + { + n =3D ((n << 1) & ~n) & ~((n >> 1) | (n >> 3)); + while (n & (n - 1)) + n &=3D n - 1; + } + if constexpr ( + !std::is_same_v>) + n *=3D 2; + VERIFY(sizeof(V) <=3D n) << "\nsizeof(V): " << sizeof(V) << "\nn: " <<= n; + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc b/lib= stdc++-v3/testsuite/experimental/simd/tests/sincos.cc new file mode 100644 index 00000000000..ced3be49136 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc @@ -0,0 +1,29 @@ +// test only floattypes +// { dg-additional-files "reference-sincos-sp.dat" } +// { dg-additional-files "reference-sincos-ep.dat" } +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/mathreference.h" +#include "bits/simd_view.h" +#include "bits/test_values.h" + +template + void + test() + { + using std::cos; + using std::sin; + using T =3D typename V::value_type; + + vir::test::setFuzzyness(2); + vir::test::setFuzzyness(1); + + const auto& testdata =3D referenceData(); + std::experimental::experimental::simd_view(testdata).for_each( + [&](const V input, const V expected_sin, const V expected_cos) { + FUZZY_COMPARE(sin(input), expected_sin) << " input =3D " << input; + FUZZY_COMPARE(sin(-input), -expected_sin) << " input =3D " << input; + FUZZY_COMPARE(cos(input), expected_cos) << " input =3D " << input; + FUZZY_COMPARE(cos(-input), expected_cos) << " input =3D " << input; + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc= b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc new file mode 100644 index 00000000000..2e7cf66b227 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc @@ -0,0 +1,166 @@ +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/conversions.h" + +using std::experimental::simd_cast; + +template + auto + gen(const F& fun) + { + if constexpr (ConstProp) + return V(fun); + else + return make_value_unknown(V(fun)); + } + +template + void + split_concat() + { + using T =3D typename V::value_type; + if constexpr (V::size() * 3 + <=3D std::experimental::simd_abi::max_fixed_size) + { + V a(0), b(1), c(2); + auto x =3D concat(a, b, c); + COMPARE(x.size(), a.size() * 3); + std::size_t i =3D 0; + for (; i < a.size(); ++i) + { + COMPARE(x[i], T(0)); + } + for (; i < 2 * a.size(); ++i) + { + COMPARE(x[i], T(1)); + } + for (; i < 3 * a.size(); ++i) + { + COMPARE(x[i], T(2)); + } + } + + if constexpr (V::size() >=3D 4) + { + const V a =3D gen([](auto i) -> T { return i; }); + constexpr auto N0 =3D V::size() / 4u; + constexpr auto N1 =3D V::size() - 2 * N0; + using V0 =3D std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + using V1 =3D std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + { + auto x =3D std::experimental::split(a); + COMPARE(std::tuple_size::value, 3u); + COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; })); + COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N0; })); + COMPARE(std::get<2>(x), V1([](auto i) -> T { return i + 2 * N0; })); + auto b =3D concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); + // a and b may have different types if a was fixed_size such that + // another ABI tag exists with equal N, then b will have the + // non-fixed-size ABI tag. + COMPARE(a.size(), b.size()); + COMPARE( + b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); })); + } + { + auto x =3D std::experimental::split(a); + COMPARE(std::tuple_size::value, 3u); + COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; })); + COMPARE(std::get<1>(x), V1([](auto i) -> T { return i + N0; })); + COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; })); + auto b =3D concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); + // a and b may have different types if a was fixed_size such that + // another ABI tag exists with equal N, then b will have the + // non-fixed-size ABI tag. + COMPARE(a.size(), b.size()); + COMPARE( + b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); })); + } + { + auto x =3D std::experimental::split(a); + COMPARE(std::tuple_size::value, 3u); + COMPARE(std::get<0>(x), V1([](auto i) -> T { return i; })); + COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N1; })); + COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; })); + auto b =3D concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); + // a and b may have different types if a was fixed_size such that + // another ABI tag exists with equal N, then b will have the + // non-fixed-size ABI tag. + COMPARE(a.size(), b.size()); + COMPARE( + b, decltype(b)([](auto i) -> T { return (N1 + i) % V::size(); })); + } + } + + if constexpr (V::size() % 3 =3D=3D 0) + { + const V a =3D gen([](auto i) -> T { return i; }); + constexpr auto N0 =3D V::size() / 3; + using V0 =3D std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + using V1 =3D std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + { + auto [x, y, z] =3D std::experimental::split(a); + COMPARE(x, V0([](auto i) -> T { return i; })); + COMPARE(y, V0([](auto i) -> T { return i + N0; })); + COMPARE(z, V0([](auto i) -> T { return i + N0 * 2; })); + auto b =3D concat(x, y, z); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + { + auto [x, y] =3D std::experimental::split(a); + COMPARE(x, V0([](auto i) -> T { return i; })); + COMPARE(y, V1([](auto i) -> T { return i + N0; })); + auto b =3D concat(x, y); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + { + auto [x, y] =3D std::experimental::split<2 * N0, N0>(a); + COMPARE(x, V1([](auto i) -> T { return i; })); + COMPARE(y, V0([](auto i) -> T { return i + 2 * N0; })); + auto b =3D concat(x, y); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + } + + if constexpr ((V::size() & 1) =3D=3D 0) + { + using std::experimental::simd; + using std::experimental::simd_abi::deduce_t; + using V0 =3D simd>; + using V2 =3D simd>; + using V3 =3D simd>; + + const V a =3D gen([](auto i) -> T { return i; }); + + std::array v2s =3D std::experimental::split(a); + int offset =3D 0; + for (V2 test : v2s) + { + COMPARE(test, V2([&](auto i) -> T { return i + offset; })); + offset +=3D 2; + } + COMPARE(concat(v2s), simd_cast(a)); + + std::array v3s =3D std::experimental::split(a); + COMPARE(v3s[0], V3([](auto i) -> T { return i; })); + COMPARE(v3s[1], V3([](auto i) -> T { return i + V3::size(); })); + COMPARE(concat(v3s), simd_cast(a)); + } + } + +template + void + test() + { + split_concat(); + split_concat(); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc b/lib= stdc++-v3/testsuite/experimental/simd/tests/splits.cc new file mode 100644 index 00000000000..31db384f798 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc @@ -0,0 +1,21 @@ +#include "bits/verify.h" + +template + void + test() + { + using M =3D typename V::mask_type; + using namespace std::experimental::parallelism_v2; + using T =3D typename V::value_type; + if constexpr (V::size() / simd_size_v * simd_size_v =3D=3D V::si= ze()) + { + M k(true); + VERIFY(all_of(k)) << k; + const auto parts =3D split>(k); + for (auto k2 : parts) + { + VERIFY(all_of(k2)) << k2; + COMPARE(typeid(k2), typeid(simd_mask)); + } + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.c= c b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc new file mode 100644 index 00000000000..51fef12a87f =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc @@ -0,0 +1,24 @@ +// test only floattypes +#include "bits/verify.h" +#include "bits/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + + using T =3D typename V::value_type; + test_values( + { +#ifdef __STDC_IEC_559__ + std::__quiet_NaN_v, std::__infinity_v, -std::__infinity_v, -0., + std::__denorm_min_v, std::__norm_min_v / 3, +#endif + +0., std::__norm_min_v, std::__finite_max_v}, + {10000}, MAKE_TESTER(acos), MAKE_TESTER(tan), MAKE_TESTER(acosh), + MAKE_TESTER(asinh), MAKE_TESTER(atanh), MAKE_TESTER(cosh), + MAKE_TESTER(sinh), MAKE_TESTER(tanh)); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floo= r.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc new file mode 100644 index 00000000000..df105530efe =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc @@ -0,0 +1,92 @@ +// test only floattypes +#include "bits/test_values.h" +#include "bits/verify.h" + +template + void + test() + { + using T =3D typename V::value_type; + constexpr T inf =3D std::__infinity_v; + constexpr T denorm_min =3D std::__denorm_min_v; + constexpr T norm_min =3D std::__norm_min_v; + constexpr T max =3D std::__finite_max_v; + constexpr T min =3D std::__finite_min_v; + test_values( + {2.1, + 2.0, + 2.9, + 2.5, + 2.499, + 1.5, + 1.499, + 1.99, + 0.99, + 0.5, + 0.499, + 0., + -2.1, + -2.0, + -2.9, + -2.5, + -2.499, + -1.5, + -1.499, + -1.99, + -0.99, + -0.5, + -0.499, + 3 << 21, + 3 << 22, + 3 << 23, + -(3 << 21), + -(3 << 22), + -(3 << 23), +#ifdef __STDC_IEC_559__ + -0., + inf, + -inf, + denorm_min, + norm_min * 0.9, + -denorm_min, + -norm_min * 0.9, +#endif + max, + norm_min, + min, + -norm_min + }, + [](const V input) { + const V expected([&](auto i) { return std::trunc(input[i]); }); + COMPARE(trunc(input), expected) << input; + }, + [](const V input) { + const V expected([&](auto i) { return std::ceil(input[i]); }); + COMPARE(ceil(input), expected) << input; + }, + [](const V input) { + const V expected([&](auto i) { return std::floor(input[i]); }); + COMPARE(floor(input), expected) << input; + }); + +#ifdef __STDC_IEC_559__ + test_values( + { +#ifdef __SUPPORT_SNAN__ + std::__signaling_NaN_v, +#endif + std::__quiet_NaN_v}, + [](const V input) { + const V expected([&](auto i) { return std::trunc(input[i]); }); + COMPARE(isnan(trunc(input)), isnan(expected)) << input; + }, + [](const V input) { + const V expected([&](auto i) { return std::ceil(input[i]); }); + COMPARE(isnan(ceil(input)), isnan(expected)) << input; + }, + [](const V input) { + const V expected([&](auto i) { return std::floor(input[i]); }); + COMPARE(isnan(floor(input)), isnan(expected)) << input; + }); +#endif + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/where.cc b/libs= tdc++-v3/testsuite/experimental/simd/tests/where.cc new file mode 100644 index 00000000000..603e5a4b262 =2D-- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc @@ -0,0 +1,119 @@ +#include "bits/verify.h" +#include "bits/make_vec.h" +#include "bits/metahelpers.h" + +template + struct Convertible + { + operator V() const { return V(4); } + }; + +template + constexpr bool + where_is_ill_formed_impl(M, const T&, float) + { + return true; + } + +template + constexpr auto + where_is_ill_formed_impl(M m, const T& v, int) + -> std::conditional_t + { + return false; + } + +template + constexpr bool + where_is_ill_formed(M m, const T& v) + { + return where_is_ill_formed_impl(m, v, int()); + } + +template + void + where_fundamental() + { + using std::experimental::where; + T x =3D T(); + where(true, x) =3D x + 1; + COMPARE(x, T(1)); + where(false, x) =3D x - 1; + COMPARE(x, T(1)); + where(true, x) +=3D T(1); + COMPARE(x, T(2)); + } + +template + void + test() + { + using M =3D typename V::mask_type; + using T =3D typename V::value_type; + where_fundamental(); + VERIFY(!(sfinae_is_callable( + [](auto x) -> decltype(where(true, x))* { return nullptr; }))); + + const V indexes([](int i) { return i + 1; }); + const M alternating_mask =3D make_mask({true, false}); + V x =3D 0; + where(alternating_mask, x) =3D indexes; + COMPARE(alternating_mask, x =3D=3D indexes); + + where(!alternating_mask, x) =3D T(2); + COMPARE(!alternating_mask, x =3D=3D T(2)) << x; + + where(!alternating_mask, x) =3D Convertible(); + COMPARE(!alternating_mask, x =3D=3D T(4)); + + x =3D 0; + COMPARE(x, T(0)); + where(alternating_mask, x) +=3D indexes; + COMPARE(alternating_mask, x =3D=3D indexes); + + x =3D 10; + COMPARE(x, T(10)); + where(!alternating_mask, x) +=3D T(1); + COMPARE(!alternating_mask, x =3D=3D T(11)); + where(alternating_mask, x) -=3D Convertible(); + COMPARE(alternating_mask, x =3D=3D T(6)); + constexpr bool fast_math =3D +#ifdef __FAST_MATH__ + true; +#else + false; +#endif + if constexpr (fast_math && std::is_floating_point_v) + where(alternating_mask, x) *=3D T(.5); + else + where(alternating_mask, x) /=3D T(2); + COMPARE(alternating_mask, x =3D=3D T(3)) << "\nx =3D " << x; + where(alternating_mask, x) *=3D T(3); + COMPARE(alternating_mask, x =3D=3D T(9)); + COMPARE(!alternating_mask, x =3D=3D T(11)); + + x =3D 10; + where(alternating_mask, x)++; + COMPARE(alternating_mask, x =3D=3D T(11)); + ++where(alternating_mask, x); + COMPARE(alternating_mask, x =3D=3D T(12)); + where(alternating_mask, x)--; + COMPARE(alternating_mask, x =3D=3D T(11)); + --where(alternating_mask, x); + --where(alternating_mask, x); + COMPARE(alternating_mask, x =3D=3D T(9)); + COMPARE(alternating_mask, -where(alternating_mask, x) =3D=3D T(-T(9))); + + const auto y =3D x; + VERIFY(where_is_ill_formed(true, y)); + VERIFY(where_is_ill_formed(true, x)); + VERIFY(where_is_ill_formed(true, V(x))); + + M test =3D alternating_mask; + where(alternating_mask, test) =3D M(true); + COMPARE(test, alternating_mask); + where(alternating_mask, test) =3D M(false); + COMPARE(test, M(false)); + where(alternating_mask, test) =3D M(true); + COMPARE(test, alternating_mask); + } --nextPart3116913.eMUbO1HJkO--