From: Matthias Kretz Date: Thu, 21 Jan 2021 11:50:32 +0000 (+0000) Subject: libstdc++: Add simd testsuite X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=02e32295b284bd4f4d038e73ee3118fb0546650e;p=gcc.git libstdc++: Add simd testsuite Add a new check-simd target to the testsuite. The new target creates a subdirectory, generates the necessary Makefiles, and spawns submakes to build and run the tests. Running this testsuite with defaults on my machine takes half of the time the dejagnu testsuite required to only determine whether to run tests. Since the simd testsuite integrated in dejagnu increased the time of the whole libstdc++ testsuite by ~100% this approach is a compromise for speed while not sacrificing coverage too much. Since the test driver is invoked individually per test executable from a Makefile, make's jobserver (-j) trivially parallelizes testing. Testing different flags and with simulator (or remote execution) is possible. E.g. `make check-simd DRIVEROPTS=-q target_list="unix{-m64,-m32}{-march=sandybridge,-march=skylake-avx512}{,- ffast-math}"` runs the testsuite 8 times in different subdirectories, using 8 different combinations of compiler flags, only outputs failing tests (-q), and prints all summaries at the end. It skips most ABI tags by default unless --run-expensive is passed to DRIVEROPTS or GCC_TEST_RUN_EXPENSIVE is not empty. To use a simulator, the CHECK_SIMD_CONFIG variable needs to point to a shell script which calls `define_target ` and set target_list as needed. E.g.: case "$target_triplet" in x86_64-*) target_list="unix{-march=sandybridge,-march=skylake-avx512} ;; powerpc64le-*) define_target power8 "-static -mcpu=power8" "/usr/bin/qemu-ppc64le -cpu power8" define_target power9 -mcpu=power9 "$HOME/bin/run_on_gcc135" target_list="power8 power9{,-ffast-math}" ;; esac 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/Makefile.in: Regenerate. * 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. --- diff --git a/libstdc++-v3/scripts/check_simd b/libstdc++-v3/scripts/check_simd new file mode 100755 index 00000000000..25acf64c841 --- /dev/null +++ b/libstdc++-v3/scripts/check_simd @@ -0,0 +1,75 @@ +#!/bin/sh + +# check_simd +# Read config from $CHECK_SIMD_CONFIG file or $target_list + +scriptdir="$(cd "${0%/*}" && pwd)" +srcdir="$1" +builddir="$2" +shift 2 +testdir="$builddir/testsuite" + +CXX="$("$builddir/scripts/testsuite_flags" --build-cxx)" +CXXFLAGS="$("$builddir/scripts/testsuite_flags" --cxxflags) $1 -Wno-psabi" +shift +INCLUDES="$("$builddir/scripts/testsuite_flags" --build-includes)" + +target_triplet=$($CXX -dumpmachine) + +define_target() { + name="$1" + flags="$2" + sim="$3" + eval "$name=\"flags=\\\"$flags\\\" +sim=\\\"$sim\\\"\"" +} + +if [ -f "$CHECK_SIMD_CONFIG" ]; then + . "$CHECK_SIMD_CONFIG" +elif [ -z "$CHECK_SIMD_CONFIG" ]; then + if [ -z "$target_list" ]; then + target_list="unix" + case "$target_triplet" in + x86_64-*) target_list="unix/-march=native" ;; + i?86-*) target_list="unix/-march=native" ;; + powerpc64le-*) target_list="unix/-mcpu=power8" ;; + aarch64-*) target_list="unix/-mcpu=cortex-a53" ;; + arm-*) target_list="unix/-mcpu=cortex-a7" ;; + esac + fi +else + echo "Error: File not found: \$CHECK_SIMD_CONFIG='$CHECK_SIMD_CONFIG'" 1>&2 + exit 1 +fi + +# define unix with no flags and no simulator: +define_target unix + +list="$target_list" + +# expand a{b,c} to a/b a/c +while [ "${list#*\{}" != "${list}" ]; do + list="$(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="${list%% *}" + if [ "$a" = "$list" ]; then + list="" + else + list="${list#${a} }" + fi + b="${a%%/*}" + eval "eval \"\$$b\"" + flags="${flags}$(echo "${a#${b}}"|sed 's#/# #g')" + subdir="simd/$(echo "$flags" | sed 's#[= /-]##g')" + rm -f "${subdir}/Makefile" + $srcdir/testsuite/experimental/simd/generate_makefile.sh \ + --destination="$testdir/$subdir" --sim="$sim" --testflags="$flags" \ + $CXX $INCLUDES $CXXFLAGS -static-libgcc -static-libstdc++ + echo "$subdir" +done diff --git a/libstdc++-v3/scripts/create_testsuite_files b/libstdc++-v3/scripts/create_testsuite_files index 52bbb5cda5a..174c24ec05a 100755 --- a/libstdc++-v3/scripts/create_testsuite_files +++ b/libstdc++-v3/scripts/create_testsuite_files @@ -27,6 +27,7 @@ tmp="${TMPDIR:-/tmp}/ctt$$" tests_file_normal="$outdir/testsuite_files" tests_file_inter="$outdir/testsuite_files_interactive" tests_file_perf="$outdir/testsuite_files_performance" +tests_file_simd="$outdir/testsuite_files_simd" 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 +grep simd/tests/ $tmp.5 > $tests_file_simd +grep -v simd/tests/ $tmp.5 > $tmp.6 + # ...more filters go here. -cp $tmp.5 $tests_file_normal +cp $tmp.6 $tests_file_normal rm $tmp* exit 0 diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am index 1342bdd9aaa..5dd109b40c9 100644 --- a/libstdc++-v3/testsuite/Makefile.am +++ b/libstdc++-v3/testsuite/Makefile.am @@ -31,7 +31,8 @@ include $(top_srcdir)/fragment.am lists_of_files = \ testsuite_files \ testsuite_files_interactive \ - testsuite_files_performance + testsuite_files_performance \ + testsuite_files_simd # This rule generates all of the testsuite_files* lists at once. ${lists_of_files}: @@ -185,6 +186,19 @@ check-performance: testsuite_files_performance ${performance_script} CXXFLAGS='$(CXXFLAGS)'; export CXXFLAGS; \ ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir}) +# 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_builddir}" "$(CXXFLAGS)" | \ + while read subdir; do \ + $(MAKE) -C "$${subdir}"; \ + tail -n20 $${subdir}/simd_testsuite.sum | \ + grep -A20 -B1 'Summary ===' >> .simd.summary; \ + done; \ + cat .simd.summary && rm .simd.summary + # Runs the testsuite in debug mode. debug_flags = "unix/-D_GLIBCXX_DEBUG" @@ -234,4 +248,4 @@ CLEANFILES = *.txt *.tst *.exe core* filebuf_* tmp* ostream_* *.log *.sum \ # To remove directories. clean-local: - rm -rf de fr debug parallel binaries normal* + rm -rf de fr debug parallel binaries normal* simd diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in index 1aac7edff7f..3900d6d87b4 100644 --- a/libstdc++-v3/testsuite/Makefile.in +++ b/libstdc++-v3/testsuite/Makefile.in @@ -380,7 +380,8 @@ AM_CPPFLAGS = $(GLIBCXX_INCLUDES) $(CPPFLAGS) lists_of_files = \ testsuite_files \ testsuite_files_interactive \ - testsuite_files_performance + testsuite_files_performance \ + testsuite_files_simd extract_symvers = $(glibcxx_builddir)/scripts/extract_symvers baseline_subdir := $(shell $(CXX) $(baseline_subdir_switch)) @@ -710,6 +711,19 @@ check-performance: testsuite_files_performance ${performance_script} CXXFLAGS='$(CXXFLAGS)'; export CXXFLAGS; \ ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir}) +# 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_builddir}" "$(CXXFLAGS)" | \ + while read subdir; do \ + $(MAKE) -C "$${subdir}"; \ + tail -n20 $${subdir}/simd_testsuite.sum | \ + grep -A20 -B1 'Summary ===' >> .simd.summary; \ + done; \ + cat .simd.summary && rm .simd.summary + check-debug: site.exp outputdir=debug; export outputdir; \ if test ! -d $${outputdir}; then \ @@ -742,7 +756,7 @@ check-performance-parallel: testsuite_files_performance ${performance_script} # To remove directories. clean-local: - rm -rf de fr debug parallel binaries normal* + rm -rf de fr debug parallel binaries normal* simd # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/libstdc++-v3/testsuite/experimental/simd/driver.sh b/libstdc++-v3/testsuite/experimental/simd/driver.sh new file mode 100755 index 00000000000..aabef316f47 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/driver.sh @@ -0,0 +1,249 @@ +#!/bin/sh + +type=float +abi=0 +name= +srcdir="$(cd "${0%/*}" && pwd)/tests" +sim="$GCC_TEST_SIMULATOR" +quiet=false +verbose=false +timeout=180 +run_expensive=false +if [ -n "$GCC_TEST_RUN_EXPENSIVE" ]; then + run_expensive=true +fi +keep_failed=false +only= + +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 otherwise). + --only Compile and run only tests matching the given pattern. +EOF +} + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + usage + exit + ;; + -q|--quiet) + quiet=true + ;; + -v|--verbose) + verbose=true + ;; + --run-expensive) + run_expensive=true + ;; + -k|--keep-failed) + keep_failed=true + ;; + --only) + only="$2" + shift + ;; + --only=*) + only="${1#--only=}" + ;; + -t|--type) + type="$2" + shift + ;; + --type=*) + type="${1#--type=}" + ;; + -a|--abi) + abi="$2" + shift + ;; + --abi=*) + abi="${1#--abi=}" + ;; + -n|--name) + name="$2" + shift + ;; + --name=*) + name="${1#--name=}" + ;; + --srcdir) + srcdir="$2" + shift + ;; + --srcdir=*) + srcdir="${1#--srcdir=}" + ;; + --sim) + sim="$2" + shift + ;; + --sim=*) + sim="${1#--sim=}" + ;; + --timeout-factor) + timeout=$(awk "BEGIN { print int($timeout * $2) }") + shift + ;; + --timeout-factor=*) + x=${1#--timeout-factor=} + timeout=$(awk "BEGIN { print int($timeout * $x) }") + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +CXX="$1" +shift +CXXFLAGS="$@" +src="${srcdir}/${name}.cc" +shorttype=$(echo $type|sed -e 's/long /l/' -e 's/unsigned /u/' -e 's/signed /s/') +testname="${name}-${shorttype}-${abi}" +exe="${testname}.exe" +log="${testname}.log" +sum="${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="" +elif [ $abi -gt 0 -a $abi -lt 10 ]; then + abi="-DEXTENDEDTESTS=$((abi-1))" +else + echo "Error: The -a argument must be a value between 0 and 9 (inclusive)." >&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=$1 + if [ $failed -eq 0 ]; then + warnings=$(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=$(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=$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=$type $abi -o $exe" +timeout $timeout "$CXX" "$src" "$@" "-D_GLIBCXX_SIMD_TESTTYPE=$type" $abi -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=$(awk "BEGIN { print int($timeout / 2) }") + timeout $timeout "./$exe" >> "$log" 2>&1 <&- +fi +verify_test $? + +# vim: sw=2 et cc=81 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..85a7f87271e --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh @@ -0,0 +1,261 @@ +#!/bin/sh + +srcdir="$(cd "${0%/*}" && pwd)" +driver="$srcdir/driver.sh" +srcdir="$srcdir/tests" +sim= +rm_logs=true +dst=. +testflags= + +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. + --testflags Force initial TESTFLAGS contents. + -d , --destination + Destination for the generated Makefile. If the directory + does not exist it is created (default: $dst). +EOF +} + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + usage + exit + ;; + --testflags) + testflags="$2" + shift + ;; + --testflags=*) + testflags="${1#--testflags=}" + ;; + -d|--destination) + dst="$2" + shift + ;; + --destination=*) + dst="${1#--destination=}" + ;; + --keep-intermediate-logs) + rm_logs=false + ;; + --srcdir) + srcdir="$2" + shift + ;; + --srcdir=*) + srcdir="${1#--srcdir=}" + ;; + --sim) + sim="$2" + shift + ;; + --sim=*) + sim="${1#--sim=}" + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +mkdir -p "$dst" +dst="$dst/Makefile" +if [ -f "$dst" ]; then + echo "Error: $dst already exists. Aborting." 1>&2 + exit 1 +fi + +CXX="$1" +shift + +echo "TESTFLAGS ?=" > "$dst" +[ -n "$testflags" ] && echo "TESTFLAGS := $testflags \$(TESTFLAGS)" >> "$dst" +echo CXXFLAGS = "$@" "\$(TESTFLAGS)" >> "$dst" +[ -n "$sim" ] && echo "export GCC_TEST_SIMULATOR = $sim" >> "$dst" +cat >> "$dst" < \$@ + @cat \$(^:log=sum) > \$(@:log=sum)${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=sum) > \$(@:log=sum)${rmline} + +EOF + done + all_types | while read t && read type; do + cat < \$@ + @cat \$(^:log=sum) > \$(@:log=sum)${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 otherwise).\n"\\ + "--only Compile and run only tests matching the given pattern.\n" + @echo "use TESTFLAGS= 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/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc new file mode 100644 index 00000000000..7d94cf47e1c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2020 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/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 = 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..78bce35f59c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc @@ -0,0 +1,30 @@ +// Copyright (C) 2020 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/metahelpers.h" + +template + void + test() + { + using T = 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/conversions.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h new file mode 100644 index 00000000000..e89221e1ede --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h @@ -0,0 +1,184 @@ +// Copyright (C) 2020 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 + +// is_conversion_undefined +/* implementation-defined + * ====================== + * §4.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 + * ========= + * §4.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. + * + * §4.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. + * + * §4.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 = false; + for (std::size_t i = 0; i < x.size(); ++i) + k[i] = 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 = {{ + 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..ee0d436f9ae --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h @@ -0,0 +1,59 @@ +// Copyright (C) 2020 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 + +template + inline M + make_mask(const std::initializer_list &init) + { + std::size_t i = 0; + M r = {}; + for (;;) + { + for (bool x : init) + { + r[i] = x; + if (++i == M::size()) + { + return r; + } + } + } + } + +template + inline V + make_vec(const std::initializer_list &init, + typename V::value_type inc = 0) + { + std::size_t i = 0; + V r = {}; + typename V::value_type base = 0; + for (;;) + { + for (auto x : init) + { + r[i] = base + x; + if (++i == V::size()) + { + return r; + } + } + base += inc; + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h new file mode 100644 index 00000000000..2ed2bb35e3c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h @@ -0,0 +1,160 @@ +// Copyright (C) 2020 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 +#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 = "sincos"; }; + struct atan { static constexpr const char *const str = "atan"; }; + struct asin { static constexpr const char *const str = "asin"; }; + struct acos { static constexpr const char *const str = "acos"; }; + struct log { static constexpr const char *const str = "ln"; }; + struct log2 { static constexpr const char *const str = "log2"; }; + struct log10 { static constexpr const char *const str = "log10"; }; +} + +template + struct testdatatype_for_function + { + template + using type = Reference; + }; + +template <> + struct testdatatype_for_function + { + template + using type = SincosReference; + }; + +template + using testdatatype_for_function_t + = 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 + = std::string("reference-") + F::str + + (sizeof(T) == 4 && std::__digits_v == 24 + && std::__max_exponent_v == 128 + ? "-sp" + : (sizeof(T) == 8 + && std::__digits_v == 53 + && std::__max_exponent_v == 1024 + ? "-dp" + : (sizeof(T) == 16 && std::__digits_v == 64 + && std::__max_exponent_v == 16384 + ? "-ep" + : (sizeof(T) == 16 && std::__digits_v == 113 + && std::__max_exponent_v == 16384 + ? "-qp" + : "-unknown")))) + + ".dat"; + return cache; + } + +template > + Array + referenceData() + { + static Array data; + if (data.data_ == nullptr) + { + FILE* file = std::fopen(filename().c_str(), "rb"); + if (file) + { + std::fseek(file, 0, SEEK_END); + const size_t size = std::ftell(file) / sizeof(Ref); + std::rewind(file); + auto mem = new Ref[size]; + static StaticDeleter _cleanup(data.data_); + data.size_ = std::fread(mem, sizeof(Ref), size, file); + data.data_ = 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/metahelpers.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h new file mode 100644 index 00000000000..e9516537e60 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h @@ -0,0 +1,164 @@ +// Copyright (C) 2020 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 +// . + +#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() = 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_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() %= 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_bit_and +{ + 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_bit_or +{ + 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_bit_xor +{ + 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_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 assign_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); } +}; + +template > + constexpr bool is_substitution_failure + = 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..a221708df39 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h @@ -0,0 +1,121 @@ +// Copyright (C) 2020 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 +// . + +#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 = decltype(begin(std::declval())); + + template + using end_type = 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() <= end; it += 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 != end) + { + fun(V([&](auto i) + { + auto ii = it + i < end ? i + 0 : 0; + return std::get<0>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii = it + i < end ? i + 0 : 0; + return std::get<1>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii = 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() <= end; it += 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 != end) + { + fun(V([&](auto i) { + auto ii = it + i < end ? i + 0 : 0; + return std::get<0>(it[ii].as_tuple()); + }), + V([&](auto i) { + auto ii = 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 + = 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_values.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h new file mode 100644 index 00000000000..01988aef327 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h @@ -0,0 +1,383 @@ +// Copyright (C) 2020 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 +#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 = f; + where(k, r) = t; + return r; + } + +template + V + epilogue_load(const typename V::value_type* mem, const std::size_t size) + { + const int rem = 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 = inputs.begin(); it + V::size() <= inputs.end(); + it += 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 = typename V::value_type; + static constexpr bool isfp = 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 = 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 <= 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 + = std::normal_distribution(0.f, + std::__max_exponent_v * .5f); + return V([&](int) { + const T mant = dist(gen); + T fp = 0; + do { + const int exp = exp_dist(gen); + fp = std::ldexp(mant, exp); + } while (fp >= abs_max || fp <= std::__denorm_min_v); + fp = 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 = 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& inputs, + F&&... fun_pack) + { + for (auto scalar_it = inputs.begin(); scalar_it != inputs.end(); + ++scalar_it) + { + for (auto it = inputs.begin(); it + V::size() <= inputs.end(); + it += 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& inputs, + RandomValues random, F&&... fun_pack) + { + test_values_2arg(inputs, fun_pack...); + for (size_t i = 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& inputs, + F&&... fun_pack) + { + for (auto scalar_it1 = inputs.begin(); scalar_it1 != inputs.end(); + ++scalar_it1) + { + for (auto scalar_it2 = inputs.begin(); scalar_it2 != inputs.end(); + ++scalar_it2) + { + for (auto it = inputs.begin(); it + V::size() <= inputs.end(); + it += 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& inputs, + RandomValues random, F&&... fun_pack) + { + test_values_3arg(inputs, fun_pack...); + for (size_t i = 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 = typename V::value_type; + if constexpr (sizeof(T) <= sizeof(double)) + { + using I = rebind_simd_t<__int_for_sizeof_t, V>; + const I abs_x = __bit_cast(abs(x)); + const I min = __bit_cast(V(std::__norm_min_v)); + const I max = __bit_cast(V(std::__finite_max_v)); + return static_simd_cast( + __bit_cast(x) == 0 || (abs_x >= min && abs_x <= max)); + } + else + { + const V abs_x = abs(x); + const V min = std::__norm_min_v; + // Make max non-const static to inhibit constprop. Otherwise the + // compiler might decide `abs_x <= max` is constexpr true, by definition + // (-ffinite-math-only) + static V max = std::__finite_max_v; + return (x == 0 && copysign(V(1), x) == V(1)) + || (abs_x >= min && abs_x <= max); + } + } + +#define MAKE_TESTER_2(name_, reference_) \ + [&](auto... inputs) { \ + ((where(!isvalid(inputs), inputs) = 1), ...); \ + const auto totest = name_(inputs...); \ + using R = std::remove_const_t; \ + auto&& expected = [&](const auto&... vs) -> const R { \ + R tmp = {}; \ + for (std::size_t i = 0; i < R::size(); ++i) \ + tmp[i] = reference_(vs[i]...); \ + return tmp; \ + }; \ + const R expect1 = expected(inputs...); \ + if constexpr (std::is_floating_point_v) \ + { \ + ((where(!isvalid(expect1), inputs) = 1), ...); \ + const R expect2 = expected(inputs...); \ + ((FUZZY_COMPARE(name_(inputs...), expect2) << "\ninputs = ") \ + << ... << inputs); \ + } \ + else \ + ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + } + +#define MAKE_TESTER_NOFPEXCEPT(name_) \ + [&](auto... inputs) { \ + ((where(!isvalid(inputs), inputs) = 1), ...); \ + using R = std::remove_const_t; \ + auto&& expected = [&](const auto&... vs) -> const R { \ + R tmp = {}; \ + for (std::size_t i = 0; i < R::size(); ++i) \ + tmp[i] = std::name_(vs[i]...); \ + return tmp; \ + }; \ + const R expect1 = expected(inputs...); \ + if constexpr (std::is_floating_point_v) \ + { \ + ((where(!isvalid(expect1), inputs) = 1), ...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + auto totest = name_(inputs...); \ + asm volatile(""); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + const R expect2 = expected(inputs...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + totest = 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 = 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 = name_(inputs...); \ + using R = std::remove_const_t; \ + auto&& expected = [&](const auto&... vs) -> const R { \ + R tmp = {}; \ + for (std::size_t i = 0; i < R::size(); ++i) \ + tmp[i] = reference_(vs[i]...); \ + return tmp; \ + }; \ + const R expect1 = expected(inputs...); \ + if constexpr (std::is_floating_point_v) \ + { \ + ((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(") \ + << ... << inputs) \ + << ") = " << totest << " != " << expect1; \ + ((where(isnan(expect1), inputs) = 0), ...); \ + ((FUZZY_COMPARE(name_(inputs...), expected(inputs...)) \ + << "\nclean = ") \ + << ... << inputs); \ + } \ + else \ + ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + } + +#define MAKE_TESTER_NOFPEXCEPT(name_) \ + [&](auto... inputs) { \ + std::feclearexcept(FE_ALL_EXCEPT); \ + auto totest = name_(inputs...); \ + ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(") \ + << ... << inputs) \ + << ")"; \ + using R = std::remove_const_t; \ + auto&& expected = [&](const auto&... vs) -> const R { \ + R tmp = {}; \ + for (std::size_t i = 0; i < R::size(); ++i) \ + tmp[i] = std::name_(vs[i]...); \ + return tmp; \ + }; \ + const R expect1 = expected(inputs...); \ + if constexpr (std::is_floating_point_v) \ + { \ + ((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(") \ + << ... << inputs) \ + << ") = " << totest << " != " << expect1; \ + ((where(isnan(expect1), inputs) = 0), ...); \ + const R expect2 = expected(inputs...); \ + std::feclearexcept(FE_ALL_EXCEPT); \ + asm volatile(""); \ + totest = 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/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h new file mode 100644 index 00000000000..3b6966dd85d --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h @@ -0,0 +1,101 @@ +// Copyright (C) 2020 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 +// . + +#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 = 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 = std::fetestexcept(FE_ALL_EXCEPT); + T val = val_; + T ref = ref_; + + T diff = 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 = value_type_t; + + where(ref == 0, val) = abs(val); + where(ref == 0, diff) = 1; + where(ref == 0, ref) = std::__norm_min_v; + where(isinf(ref) && ref == val, ref) + = 0; // where(val_ == ref_) = 0 below will fix it up + + where(val == 0, ref) = abs(ref); + where(val == 0, diff) += 1; + where(val == 0, val) = std::__norm_min_v; + + using I = decltype(fpclassify(std::declval())); + I exp = {}; + frexp(ref, &exp); + // lower bound for exp must be min_exponent to scale the resulting + // difference from a denormal correctly + exp = max(exp, I(std::__min_exponent_v)); + diff += ldexp(abs(ref - val), std::__digits_v - exp); + where(val_ == ref_ || (isnan(val_) && isnan(ref_)), diff) = 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..5da47b35536 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h @@ -0,0 +1,353 @@ +// Copyright (C) 2020 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 +// . + +#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 = signed char; +using uchar = unsigned char; +using ushort = unsigned short; +using uint = unsigned int; +using ulong = unsigned long; +using llong = long long; +using ullong = unsigned long long; +using ldouble = long double; +using wchar = wchar_t; +using char16 = char16_t; +using char32 = char32_t; + +template + T + make_value_unknown(const T& x) + { + if constexpr (std::is_constructible_v) + { + const volatile T& y = x; + return y; + } + else + { + T y = x; + asm("" : "+m"(y)); + return y; + } + } + +class verify +{ + const bool m_failed = 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] << " == " << std::hexfloat << x[0] + << std::defaultfloat << ')'; + for (unsigned i = 1; i < x.size(); ++i) + { + ss << (i % 4 == 0 ? ",\n(" : ", (") << x[i] + << " == " << std::hexfloat << x[i] << std::defaultfloat + << ')'; + } + } + else + { + ss << +x[0]; + for (unsigned i = 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 = 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 = static_cast(x); + for (std::size_t i = 0; i < n; ++i) + { + __builtin_fprintf(stderr, (i && i % 4 == 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 = 0; +#ifdef __x86_64__ + asm volatile("lea 0(%%rip),%0" : "=r"(_ip)); +#elif defined __i386__ + asm volatile("1: movl $1b,%0" : "=r"(_ip)); +#elif defined __arm__ + asm volatile("mov %0,pc" : "=r"(_ip)); +#elif defined __aarch64__ + asm volatile("adr %0,." : "=r"(_ip)); +#endif + return _ip; + } +}; + +#if __FLT_EVAL_METHOD__ != 0 +template + [[gnu::always_inline]] inline decltype(auto) + force_fp_truncation(const T& x) + { + namespace stdx = std::experimental; + if constexpr (stdx::is_simd_v) + { + using U = typename T::value_type; + if constexpr (std::is_floating_point_v + && sizeof(U) <= 8 && (sizeof(T) < 16 || std::is_same_v< + T, stdx::fixed_size_simd>)) + { + T y = x; + asm("" : "+m"(y)); + return y; + } + else + return x; + } + else if constexpr (std::is_floating_point_v && sizeof(T) <= 8) + { + T y = x; + asm("" : "+m"(y)); + return y; + } + else + return x; + } + +#define COMPARE(_a, _b) \ + [&](auto&& _aa, auto&& _bb) { \ + return verify(std::experimental::all_of(_aa == _bb), verify::get_ip(), \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + "all_of(" #_a " == " #_b ")", #_a " = ", _aa, \ + "\n" #_b " = ", _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 == _bb), verify::get_ip(), \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + "all_of(" #_a " == " #_b ")", #_a " = ", _aa, \ + "\n" #_b " = ", _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 conditionally + // executed +#define ULP_COMPARE(_a, _b, _allowed_distance) \ + [&](auto&& _aa, auto&& _bb) { \ + const bool success = std::experimental::all_of( \ + vir::test::ulp_distance(_aa, _bb) <= (_allowed_distance)); \ + return verify(success, verify::get_ip(), __FILE__, __LINE__, \ + __PRETTY_FUNCTION__, "all_of(" #_a " ~~ " #_b ")", \ + #_a " = ", _aa, "\n" #_b " = ", _bb, "\ndistance = ", \ + success ? 0 : vir::test::ulp_distance_signed(_aa, _bb)); \ + }((_a), (_b)) + +namespace vir { + namespace test + { + template + inline T _S_fuzzyness = 0; + + template + void + setFuzzyness(T x) + { _S_fuzzyness = 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 == 0 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 1 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 2 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 3 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 4 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 5 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 6 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 7 + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); + invoke_test>>(int()); +#elif EXTENDEDTESTS == 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..c107de3380b --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc @@ -0,0 +1,104 @@ +// Copyright (C) 2020 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/metahelpers.h" + +enum unscoped_enum +{ foo }; + +enum class scoped_enum +{ bar }; + +struct convertible +{ + operator int(); + operator float(); +}; + +template + void + test() + { + using T = typename V::value_type; + VERIFY(std::experimental::is_simd_v); + VERIFY(std::experimental::is_abi_tag_v); + + { + V x; // not initialized + x = V{}; // default broadcasts 0 + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + x = V(); // default broadcasts 0 + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + x = 0; + COMPARE(x, V(0)); + COMPARE(x, V()); + COMPARE(x, V{}); + + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(T(x[i]), T(0)) << "i = " << i; + COMPARE(x[i], T(0)) << "i = " << i; + } + } + + V x = 3; + V y = T(0); + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(x[i], T(3)) << "i = " << i; + COMPARE(y[i], T(0)) << "i = " << i; + } + y = 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/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc new file mode 100644 index 00000000000..df169e100de --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc @@ -0,0 +1,169 @@ +// Copyright (C) 2020 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/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 = 0; i < V::size(); ++i) + { + data[i] = static_cast(v[i]); + } + } + + template + constexpr T + operator()(I) + { return data[I::value]; } + }; + +template + struct gen_seq_t + { + using From = typename V::value_type; + const size_t N = cvt_input_data.size(); + size_t offset = 0; + + constexpr void + operator++() + { offset += V::size(); } + + explicit constexpr operator bool() const + { return offset < N; } + + template + constexpr From + operator()(I) const + { + size_t i = 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 = typename V::value_type; + constexpr auto N = V::size(); + if constexpr (N <= std::experimental::simd_abi::max_fixed_size) + { + using W = std::experimental::fixed_size_simd; + + if constexpr (std::is_integral_v) + { + using A = typename V::abi_type; + using TU = std::make_unsigned_t; + using TS = 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 + = decltype(vir::test::sfinae_is_callable_t(foo())); + + COMPARE(is_simd_cast_allowed::value, + std::__digits::value <= std::__digits::value + && std::__finite_max::value + <= 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 = " << seq; + auto test = 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 = 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..eef26108f5f --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc @@ -0,0 +1,106 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" +#include + +template + auto + verify_no_fp_exceptions(F&& fun) + { + std::feclearexcept(FE_ALL_EXCEPT); + auto r = fun(); + COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0); + return r; + } + +#define NOFPEXCEPT(...) verify_no_fp_exceptions([&]() { return __VA_ARGS__; }) + +template + void + test() + { + using T = typename V::value_type; + using intv = std::experimental::fixed_size_simd; + constexpr T inf = std::__infinity_v; + constexpr T denorm_min = std::__infinity_v; + constexpr T nan = std::__quiet_NaN_v; + constexpr T max = std::__finite_max_v; + constexpr T norm_min = std::__norm_min_v; + test_values( + {0., 1., -1., +#if __GCC_IEC_559 >= 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 = 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/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc new file mode 100644 index 00000000000..e2d90dd1e3f --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc @@ -0,0 +1,85 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + using int_v = std::experimental::fixed_size_simd; + using T = typename V::value_type; + constexpr auto denorm_min = std::__denorm_min_v; + constexpr auto norm_min = std::__norm_min_v; + constexpr auto max = std::__finite_max_v; + constexpr auto nan = std::__quiet_NaN_v; + constexpr auto inf = 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 >= 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] = std::frexp(input[i], &exp); + return exp; + }); + int_v exponent = {}; + const V fraction = frexp(input, &exponent); + COMPARE(fraction, expectedFraction) << ", input = " << 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 unspecified. + // + // If x is positive infinity (negative infinity), positive infinity + // (negative infinity) is returned, and the value of *exp is unspecified. + // 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 = {}; + const V fraction = frexp(input, &exponent); + COMPARE(isnan(fraction), isnan(expectedFraction)) + << fraction << ", input = " << input + << ", delta: " << fraction - expectedFraction; + COMPARE(isinf(fraction), isinf(expectedFraction)) + << fraction << ", input = " << input + << ", delta: " << fraction - expectedFraction; + COMPARE(signbit(fraction), signbit(expectedFraction)) + << fraction << ", input = " << 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..221064dc476 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc @@ -0,0 +1,58 @@ +// Copyright (C) 2020 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/metahelpers.h" + +template + struct call_generator + { + template + auto + operator()(const F& f) -> decltype(V(f)); + }; + +using schar = signed char; +using uchar = unsigned char; +using ullong = unsigned long long; + +template + void + test() + { + using T = typename V::value_type; + V x([](int) { return T(1); }); + COMPARE(x, V(1)); + // unconditionally returns int from generator lambda + x = V([](int) { return 1; }); + COMPARE(x, V(1)); + x = 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) <= sizeof(uchar))); + COMPARE(sfinae_is_callable(call_generator()), + (std::is_floating_point::value)); + + COMPARE(sfinae_is_callable(call_generator()), + std::__finite_max_v >= std::__finite_max_v + && std::__digits_v >= 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..0c8e55983a2 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc @@ -0,0 +1,151 @@ +// test only floattypes +// Copyright (C) 2020 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/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 = std::abs(x); + y = std::abs(y); + z = 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 == y && y == z) + return x * std::sqrt(T(3)); + else if (z == 0 && y == 0) + return x; + else if (x == 0 && z == 0) + return y; + else if (x == 0 && y == 0) + return z; + else + { + T hi = std::max(std::max(x, y), z); + T lo0 = std::min(std::max(x, y), z); + T lo1 = std::min(x, y); + int e = 0; + hi = std::frexp(hi, &e); + lo0 = std::ldexp(lo0, -e); + lo1 = std::ldexp(lo1, -e); + T lo = 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 reference + + using T = 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 + = [](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 + = [](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_operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc new file mode 100644 index 00000000000..975e69a9e35 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc @@ -0,0 +1,218 @@ +// Copyright (C) 2020 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 <= End) + { + fun(std::integral_constant()); + if constexpr (Begin < End) + { + for_constexpr(static_cast(fun)); + } + } + } + +template + void + test() + { + using T = typename V::value_type; + if constexpr (std::is_integral_v) + { + constexpr int nbits(sizeof(T) * __CHAR_BIT__); + constexpr int n_promo_bits + = std::max(nbits, int(sizeof(int) * __CHAR_BIT__)); + + // complement + COMPARE(~V(), V(~T())); + COMPARE(~V(~T()), V()); + + { // modulus + V x = make_vec({3, 4}, 2); + COMPARE(x % x, V(0)); + V y = x - 1; + COMPARE(x % y, V(1)); + y = x + 1; + COMPARE(x % y, x); + if (std::is_signed::value) + { + x = -x; + COMPARE(x % y, x); + x = -y; + COMPARE(x % y, V(0)); + x = x - 1; + COMPARE(x % y, V(-1)); + x %= y; + COMPARE(x, V(-1)); + } + } + + { // bit_and + V x = make_vec({3, 4, 5}, 8); + COMPARE(x & x, x); + COMPARE(x & ~x, V()); + COMPARE(x & V(), V()); + COMPARE(V() & x, V()); + V y = make_vec({1, 5, 3}, 8); + COMPARE(x & y, make_vec({1, 4, 1}, 8)); + x &= y; + COMPARE(x, make_vec({1, 4, 1}, 8)); + } + + { // bit_or + V x = make_vec({3, 4, 5}, 8); + COMPARE(x | x, x); + COMPARE(x | ~x, ~V()); + COMPARE(x | V(), x); + COMPARE(V() | x, x); + V y = make_vec({1, 5, 3}, 8); + COMPARE(x | y, make_vec({3, 5, 7}, 8)); + x |= y; + COMPARE(x, make_vec({3, 5, 7}, 8)); + } + + { // bit_xor + V x = make_vec({3, 4, 5}, 8); + COMPARE(x ^ x, V()); + COMPARE(x ^ ~x, ~V()); + COMPARE(x ^ V(), x); + COMPARE(V() ^ x, x); + V y = make_vec({1, 5, 3}, 8); + COMPARE(x ^ y, make_vec({2, 1, 6}, 0)); + x ^= y; + COMPARE(x, make_vec({2, 1, 6}, 0)); + } + + { // bit_shift_left + // Note: + // - negative RHS or RHS >= 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 = 0; i < nbits - 1; ++i) + { + COMPARE(V(1) << i, V(T(1) << i)) << "i: " << i; + } + for_constexpr( + [](auto shift_ic) { + constexpr int shift = shift_ic; + const V seq = make_value_unknown(V([&](T i) { + if constexpr (std::is_signed_v) + { + const T max = std::__finite_max_v >> shift; + return max == 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 = make_vec({0, 1}, nbits - 2); + seq %= nbits - 1; + COMPARE(make_vec({0, 1}, 0) << seq, + V([&](auto i) { return T(T(i & 1) << seq[i]); })) + << "seq = " << 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 = nbits - 1; + COMPARE(V(1) << shift_count, V(T(1) << shift_count)); + constexpr T max = // 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 >= #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 = 1; s < nbits; ++s) + { + COMPARE(V(~T()) >> V(s), V(T(~T()) >> s)) << "s: " << s; + } + for (int s = 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 = 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 = " << seq; + COMPARE(make_value_unknown(V(1)) >> make_value_unknown(seq), + V([&](auto i) { return T(T(1) >> seq[i]); })) + << "seq = " << seq; + } + for_constexpr([](auto shift_ic) { + constexpr int shift = shift_ic; + const V seq = make_value_unknown(V([&](int i) { + using U = 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_scalbln_modf.cc b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc new file mode 100644 index 00000000000..6d994572bf8 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc @@ -0,0 +1,169 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T = typename V::value_type; + + // See https://sourceware.org/bugzilla/show_bug.cgi?id=18031 + const bool modf_is_broken = [] { + volatile T x = T(5e20) / 7; + T tmp; + return std::fabs(std::modf(x, &tmp)) >= 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 = ldexp(input, exp); + using R = std::remove_const_t; + auto&& expected = [&](const auto& v) -> const R { + R tmp = {}; + using std::ldexp; + for (std::size_t i = 0; i < R::size(); ++i) + { + tmp[i] = ldexp(v[i], exp); + } + return tmp; + }; + const R expect1 = expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "ldexp(" << input << ", " << exp << ") = " << totest + << " != " << expect1; + FUZZY_COMPARE(ldexp(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean = " << iif(isnan(expect1), 0, input); + } + }, + [](const V input) { + for (int exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000}) + { + const auto totest = scalbn(input, exp); + using R = std::remove_const_t; + auto&& expected = [&](const auto& v) -> const R { + R tmp = {}; + using std::scalbn; + for (std::size_t i = 0; i < R::size(); ++i) + { + tmp[i] = scalbn(v[i], exp); + } + return tmp; + }; + const R expect1 = expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "scalbn(" << input << ", " << exp << ") = " << totest + << " != " << expect1; + FUZZY_COMPARE(scalbn(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean = " << iif(isnan(expect1), 0, input); + } + }, + [](const V input) { + for (long exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000}) + { + const auto totest = scalbln(input, exp); + using R = std::remove_const_t; + auto&& expected = [&](const auto& v) -> const R { + R tmp = {}; + using std::scalbln; + for (std::size_t i = 0; i < R::size(); ++i) + { + tmp[i] = scalbln(v[i], exp); + } + return tmp; + }; + const R expect1 = expected(input); + COMPARE(isnan(totest), isnan(expect1)) + << "scalbln(" << input << ", " << exp << ") = " << totest + << " != " << expect1; + FUZZY_COMPARE(scalbln(iif(isnan(expect1), 0, input), exp), + expected(iif(isnan(expect1), 0, input))) + << "\nclean = " << iif(isnan(expect1), 0, input); + } + }, + [modf_is_broken](const V input) { + if (modf_is_broken) + return; + V integral = {}; + const V totest = modf(input, &integral); + auto&& expected = [&](const auto& v) -> std::pair { + std::pair tmp = {}; + using std::modf; + for (std::size_t i = 0; i < V::size(); ++i) + { + typename V::value_type tmp2; + tmp.first[i] = modf(v[i], &tmp2); + tmp.second[i] = tmp2; + } + return tmp; + }; + const auto expect1 = expected(input); +#ifdef __STDC_IEC_559__ + COMPARE(isnan(totest), isnan(expect1.first)) + << "modf(" << input << ", iptr) = " << totest << " != " << expect1; + COMPARE(isnan(integral), isnan(expect1.second)) + << "modf(" << input << ", iptr) = " << totest << " != " << expect1; + COMPARE(isnan(totest), isnan(integral)) + << "modf(" << input << ", iptr) = " << totest << " != " << expect1; + const V clean = iif(isnan(totest), V(), input); +#else + const V clean = iif(isnormal(input), input, V()); +#endif + const auto expect2 = expected(clean); + COMPARE(modf(clean, &integral), expect2.first) << "\nclean = " << 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..994227c7d5a --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc @@ -0,0 +1,229 @@ +// Copyright (C) 2020 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/conversions.h" + +template + void + load_store() + { + // types, tags, and constants + using T = typename V::value_type; + auto&& gen = make_vec; + using std::experimental::element_aligned; + using std::experimental::vector_aligned; + + // stride_alignment: consider V::size() == 6. The only reliable alignment 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). + // => the LSB determines the stride alignment + constexpr size_t stride_alignment = size_t(1) << __builtin_ctz(V::size()); + using stride_aligned_t = std::conditional_t< + V::size() == stride_alignment, decltype(vector_aligned), + std::experimental::overaligned_tag>; + constexpr stride_aligned_t stride_aligned = {}; + constexpr size_t alignment + = 2 * std::experimental::memory_alignment_v; + constexpr auto overaligned = std::experimental::overaligned; + const V indexes_from_0([](auto i) { return i; }); + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(indexes_from_0[i], T(i)); + } + + // loads + cvt_inputs test_values; + + constexpr auto mem_size + = test_values.size() > 3 * V::size() ? test_values.size() : 3 * V::size(); + alignas(std::experimental::memory_alignment_v * 2) U mem[mem_size] + = {}; + alignas(std::experimental::memory_alignment_v * 2) + T reference[mem_size] + = {}; + for (std::size_t i = 0; i < test_values.size(); ++i) + { + const U value = test_values[i]; + mem[i] = value; + reference[i] = static_cast(value); + } + for (std::size_t i = test_values.size(); i < mem_size; ++i) + { + mem[i] = U(i); + reference[i] = mem[i]; + } + + V x(&mem[V::size()], stride_aligned); + auto&& compare = [&](const std::size_t offset) { + static int n = 0; + const V ref(&reference[offset], element_aligned); + for (auto i = 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 = " << offset << "\n x = " << x + << "\nreference = " << ref << "\nx == ref = " << (x == ref) + << "\ncall no. " << n; + } + ++n; + }; + compare(V::size()); + x = V{mem, overaligned}; + compare(0); + x = {&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 = 0; i < mem_size - V::size(); ++i) + { + x.copy_from(&mem[i], element_aligned); + compare(i); + } + + for (std::size_t i = 0; i < test_values.size(); ++i) + { + mem[i] = U(i); + } + x = indexes_from_0; + using M = typename V::mask_type; + const M alternating_mask = make_mask({0, 1}); + where(alternating_mask, x).copy_from(&mem[V::size()], stride_aligned); + + const V indexes_from_size = gen({T(V::size())}, 1); + COMPARE(x == indexes_from_size, alternating_mask) + << "x: " << x << "\nindexes_from_size: " << indexes_from_size; + COMPARE(x == indexes_from_0, !alternating_mask); + where(alternating_mask, x).copy_from(&mem[1], element_aligned); + + const V indexes_from_1 = gen({1, 2, 3, 4}, 4); + COMPARE(x == indexes_from_1, alternating_mask); + COMPARE(x == indexes_from_0, !alternating_mask); + where(!alternating_mask, x).copy_from(mem, overaligned); + COMPARE(x == indexes_from_0, !alternating_mask); + COMPARE(x == indexes_from_1, alternating_mask); + + x = where(alternating_mask, V()).copy_from(&mem[V::size()], stride_aligned); + COMPARE(x == indexes_from_size, alternating_mask); + COMPARE(x == 0, !alternating_mask); + + x = where(!alternating_mask, V()).copy_from(&mem[1], element_aligned); + COMPARE(x == indexes_from_1, !alternating_mask); + COMPARE(x == 0, alternating_mask); + + // stores + auto&& init_mem = [&mem](U init) { + for (auto i = mem_size; i; --i) + { + mem[i - 1] = init; + } + }; + init_mem(-1); + x = indexes_from_1; + x.copy_to(&mem[V::size()], stride_aligned); + std::size_t i = 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 = 1; i <= 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 = 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 = 0; i < V::size() + 1; ++i) + { + COMPARE(mem[i], U(-1)); + } + for (; i < 2 * V::size(); i += 2) + { + COMPARE(mem[i], U(i - V::size())); + } + for (i = V::size() + 2; i < 2 * V::size(); i += 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..29c686db697 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc @@ -0,0 +1,83 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/mathreference.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + + using T = typename V::value_type; + constexpr T nan = std::__quiet_NaN_v; + constexpr T inf = std::__infinity_v; + constexpr T denorm_min = std::__denorm_min_v; + constexpr T norm_min = std::__norm_min_v; + constexpr T min = std::__finite_min_v; + constexpr T max = 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..7fc8201caf6 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2020 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/metahelpers.h" + +template + void + test() + { + using M = typename V::mask_type; + static_assert(std::is_convertible::value, + "A smart_reference must be convertible to bool."); + static_assert( + std::is_same() + == true)>::value, + "A smart_reference must be comparable against bool."); + static_assert( + vir::test::sfinae_is_callable( + [](auto&& a, auto&& b) -> decltype(std::declval() + == std::declval()) { + return {}; + }), + "A smart_reference must be comparable against bool."); + VERIFY(std::experimental::is_simd_mask_v); + + { + M x; // uninitialized + x = M{}; // default broadcasts 0 + COMPARE(x, M(false)); + COMPARE(x, M()); + COMPARE(x, M{}); + x = M(); // default broadcasts 0 + COMPARE(x, M(false)); + COMPARE(x, M()); + COMPARE(x, M{}); + x = x; + for (std::size_t i = 0; i < M::size(); ++i) + { + COMPARE(x[i], false); + } + } + + M x(true); + M y(false); + for (std::size_t i = 0; i < M::size(); ++i) + { + COMPARE(x[i], true); + COMPARE(y[i], false); + } + y = M(true); + COMPARE(x, y); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc new file mode 100644 index 00000000000..8cec912250a --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2020 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" + +namespace stdx = std::experimental; + +template + void + conversions() + { + using ToV = typename To::simd_type; + + using stdx::simd_cast; + using stdx::static_simd_cast; + using stdx::__proposed::resizing_simd_cast; + + auto x = resizing_simd_cast(From()); + COMPARE(typeid(x), typeid(To)); + COMPARE(x, To()); + + x = resizing_simd_cast(From(true)); + const To ref = ToV([](auto i) { return i; }) < int(From::size()); + COMPARE(x, ref) << "converted from: " << From(true); + + const ullong all_bits = ~ullong() >> (64 - From::size()); + for (ullong bit_pos = 1; bit_pos /*until overflow*/; bit_pos *= 2) + { + for (ullong bits : {bit_pos & all_bits, ~bit_pos & all_bits}) + { + const auto from = From::__from_bitset(bits); + const auto to = resizing_simd_cast(from); + COMPARE(to, To::__from_bitset(bits)) + << "\nfrom: " << from << "\nbits: " << std::hex << bits << std::dec; + for (std::size_t i = 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 = stdx::rebind_simd_t< + T, stdx::resize_simd_t, V>>; + }; + +template + struct rebind_or_max_fixed>> + { + using type = stdx::rebind_simd_t; + }; + +template + void + apply_abis() + { + using M0 = typename rebind_or_max_fixed::type; + using M1 = stdx::native_simd_mask; + using M2 = stdx::simd_mask; + using M3 = 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 = 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_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc new file mode 100644 index 00000000000..e1760e3f37f --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc @@ -0,0 +1,102 @@ +// Copyright (C) 2020 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/metahelpers.h" + +template + constexpr bool assign_should_work + = std::is_same::value + || (std::is_same>::value + && std::is_same::value); + +template + constexpr bool assign_should_not_work = !assign_should_work; + +template + std::enable_if_t> + implicit_conversions_test() + { + L x = R(true); + COMPARE(x, L(true)); + x = R(false); + COMPARE(x, L(false)); + R y(false); + y[0] = true; + x = y; + L ref(false); + ref[0] = true; + COMPARE(x, ref); + } + +template + std::enable_if_t> + implicit_conversions_test() + { + VERIFY((is_substitution_failure) ); + } + +template + void + test() + { + using M = 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..0f43428b7c6 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc @@ -0,0 +1,161 @@ +// Copyright (C) 2020 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" + +// simd_mask generator functions +template + M + make_mask(const std::initializer_list& init) + { + std::size_t i = 0; + M r = {}; + for (;;) + { + for (bool x : init) + { + r[i] = x; + if (++i == M::size()) + { + return r; + } + } + } + } + +template + M + make_alternating_mask() + { + return make_mask({false, true}); + } + +template + void + test() + { + using M = typename V::mask_type; + // loads + constexpr size_t alignment = 2 * std::experimental::memory_alignment_v; + alignas(alignment) bool mem[3 * M::size()]; + std::memset(mem, 0, sizeof(mem)); + for (std::size_t i = 1; i < sizeof(mem) / sizeof(*mem); i += 2) + { + COMPARE(mem[i - 1], false); + mem[i] = true; + } + using std::experimental::element_aligned; + using std::experimental::vector_aligned; + constexpr size_t stride_alignment + = 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 = std::conditional_t< + M::size() == stride_alignment, decltype(vector_aligned), + std::experimental::overaligned_tag>; + constexpr stride_aligned_t stride_aligned = {}; + constexpr auto overaligned = std::experimental::overaligned; + + const M alternating_mask = make_alternating_mask(); + + M x(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : alternating_mask) + << x.__to_bitset() + << ", alternating_mask: " << alternating_mask.__to_bitset(); + x = {&mem[1], element_aligned}; + COMPARE(x, !alternating_mask); + x = M{mem, overaligned}; + COMPARE(x, alternating_mask); + + x.copy_from(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : alternating_mask); + x.copy_from(&mem[1], element_aligned); + COMPARE(x, !alternating_mask); + x.copy_from(mem, vector_aligned); + COMPARE(x, alternating_mask); + + x = !alternating_mask; + where(alternating_mask, x).copy_from(&mem[M::size()], stride_aligned); + COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : M{true}); + x = M(true); // 1111 + where(alternating_mask, x).copy_from(&mem[1], element_aligned); // load .0.0 + COMPARE(x, !alternating_mask); // 1010 + where(alternating_mask, x).copy_from(mem, overaligned); // load .1.1 + COMPARE(x, M{true}); // 1111 + + // stores + memset(mem, 0, sizeof(mem)); + x = M(true); + x.copy_to(&mem[M::size()], stride_aligned); + std::size_t i = 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 = 1; i <= 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 = 0; i < M::size(); ++i) + { + COMPARE(mem[i], (i & 1) == 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 = 0; i < M::size(); ++i) + { + COMPARE(mem[i], i % 2 == 0); + } + for (; i < 3 * M::size(); ++i) + { + COMPARE(mem[i], false); + } + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc new file mode 100644 index 00000000000..738b97c3dca --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc @@ -0,0 +1,111 @@ +// Copyright (C) 2020 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/metahelpers.h" + +using schar = signed char; +using uchar = unsigned char; +using ushort = unsigned short; +using uint = unsigned int; +using ulong = unsigned long; +using llong = long long; +using ullong = unsigned long long; +using ldouble = long double; +using wchar = wchar_t; +using char16 = char16_t; +using char32 = 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 = 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..58255cf1e1b --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2020 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/metahelpers.h" + +template + void + test() + { + using M = typename V::mask_type; + { // compares + M x(true), y(false); + VERIFY(all_of(x == x)); + VERIFY(all_of(x != y)); + VERIFY(all_of(y != x)); + VERIFY(!all_of(x != x)); + VERIFY(!all_of(x == y)); + VERIFY(!all_of(y == x)); + } + { // subscripting + M x(true); + for (std::size_t i = 0; i < M::size(); ++i) + { + COMPARE(x[i], true) << "\nx: " << x << ", i: " << i; + x[i] = !x[i]; + } + COMPARE(x, M{false}); + for (std::size_t i = 0; i < M::size(); ++i) + { + COMPARE(x[i], false) << "\nx: " << x << ", i: " << i; + x[i] = !x[i]; + } + COMPARE(x, M{true}); + } + { // negation + M x(false); + M y = !x; + COMPARE(y, M{true}); + COMPARE(!y, x); + } + } + diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc new file mode 100644 index 00000000000..1190eaf5457 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc @@ -0,0 +1,226 @@ +// Copyright (C) 2020 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/metahelpers.h" + +// simd_mask generator functions +template + M + make_mask(const std::initializer_list& init) + { + std::size_t i = 0; + M r = {}; + for (;;) + { + for (bool x : init) + { + r[i] = x; + if (++i == M::size()) + { + return r; + } + } + } + } + +template + M + make_alternating_mask() + { + return make_mask({false, true}); + } + +template + void + test() + { + using M = typename V::mask_type; + const M alternating_mask = make_alternating_mask(); + COMPARE(alternating_mask[0], false); // assumption below + auto&& gen = 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() == 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 = int(M::size() / 2 - 1); i >= 0; --i) + { + x[i] = true; + COMPARE(find_first_set(x), i) << x; + } + x = M(false); + for (int i = int(M::size() - 1); i >= 0; --i) + { + x[i] = 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 = 0; i < int(M::size()); ++i) + { + x[i] = 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) == 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..bce01264f3c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc @@ -0,0 +1,107 @@ +// test only floattypes +// Copyright (C) 2020 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/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T = typename V::value_type; + constexpr T inf = std::__infinity_v; + constexpr T nan = std::__quiet_NaN_v; + constexpr T denorm_min = std::__denorm_min_v; + constexpr T norm_min = std::__norm_min_v; + constexpr T max = 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 constexpr. + // (error: '(1.0e+0l + 4.94065645841246544176568792868221e-324l)' is not a + // constant expression) + const T after_one = 1 + std::__epsilon_v; + const T before_one = (2 - std::__epsilon_v) / 2; +#else + constexpr T after_one = 1 + std::__epsilon_v; + constexpr T before_one = (2 - std::__epsilon_v) / 2; +#endif + const std::initializer_list + input_values = {+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(erfc), + 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 can be + // wrong (up to 1 ULP) +#if __FLT_EVAL_METHOD__ == 1 + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(0); +#elif __FLT_EVAL_METHOD__ == 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..57b7b3aeb5c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc @@ -0,0 +1,79 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + using T = 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(isgreaterequal), + MAKE_TESTER_NOFPEXCEPT(isless), MAKE_TESTER_NOFPEXCEPT(islessequal), + MAKE_TESTER_NOFPEXCEPT(islessgreater), MAKE_TESTER_NOFPEXCEPT(isunordered)); + } 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..a04cd34e3d4 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc @@ -0,0 +1,1072 @@ +// Copyright (C) 2020 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/metahelpers.h" + +// type with sizeof(char) but different signedness +using xchar = std::conditional_t, schar, uchar>; + +using vschar = std::experimental::native_simd; +using vuchar = std::experimental::native_simd; +using vshort = std::experimental::native_simd; +using vushort = std::experimental::native_simd; +using vint = std::experimental::native_simd; +using vuint = std::experimental::native_simd; +using vlong = std::experimental::native_simd; +using vulong = std::experimental::native_simd; +using vllong = std::experimental::native_simd; +using vullong = std::experimental::native_simd; +using vfloat = std::experimental::native_simd; +using vdouble = std::experimental::native_simd; +using vldouble = std::experimental::native_simd; +using vchar = std::experimental::native_simd; +using vxchar = std::experimental::native_simd; + +template + using vi8 = std::experimental::fixed_size_simd; +template + using vi16 = std::experimental::fixed_size_simd; +template + using vf32 = std::experimental::fixed_size_simd; +template + using vi32 = std::experimental::fixed_size_simd; +template + using vf64 = std::experimental::fixed_size_simd; +template + using vi64 = std::experimental::fixed_size_simd; +template + using vl = typename std::conditional, + vi32>::type; + +template + void + binary_op_return_type() + { + using namespace vir::test; + static_assert(std::is_same::value, ""); + using AC = std::add_const_t; + using BC = 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 = typename V::value_type; + namespace simd_abi = 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) == 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 = 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) == 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) == 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) == 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) == 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) == 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) == 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) == 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() <= 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() <= 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() <= 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..cee696cc69b --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc @@ -0,0 +1,297 @@ +// Copyright (C) 2020 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 = typename V::mask_type; + using T = typename V::value_type; + constexpr auto min = std::__finite_min_v; + constexpr auto norm_min = std::__norm_min_v; + constexpr auto max = std::__finite_max_v; + { // compares + COMPARE(V(0) == make_vec({0, 1}, 0), make_mask({1, 0})); + COMPARE(V(0) == make_vec({0, 1, 2}, 0), make_mask({1, 0, 0})); + COMPARE(V(1) == make_vec({0, 1, 2}, 0), make_mask({0, 1, 0})); + COMPARE(V(2) == 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 = 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_ <= lo_) + continue; + + for (std::size_t pos = 0; pos < V::size(); ++pos) + { + V lo = lo_; + V hi = hi_; + lo[pos] = 0; // have a different value in the vector in case + hi[pos] = 1; // this affects neighbors + COMPARE(hi, hi); + VERIFY(all_of(hi != lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(lo != hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(hi != hi)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(hi == lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(none_of(lo == 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 <= lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi <= 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 >= lo)) << "hi: " << hi << ", lo: " << lo; + VERIFY(all_of(hi >= hi)) << "hi: " << hi << ", lo: " << lo; + } + } + } + } + { // subscripting + V x = max; + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(x[i], max); + x[i] = 0; + } + COMPARE(x, V{0}); + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(x[i], T(0)); + x[i] = 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 = V([](auto i) -> T { return i; }); + for (std::size_t i = 0; i < V::size(); ++i) + { + COMPARE(x[i], T(i)); + } + for (std::size_t i = 0; i + 1 < V::size(); i += 2) + { + using std::swap; + swap(x[i], x[i + 1]); + } + for (std::size_t i = 0; i + 1 < V::size(); i += 2) + { + COMPARE(x[i], T(i + 1)) << x; + COMPARE(x[i + 1], T(i)) << x; + } + x = 1; + V y = 0; + COMPARE(x[0], T(1)); + x[0] = y[0]; // make sure non-const smart_reference assignment works + COMPARE(x[0], T(0)); + x = 1; + x[0] = x[0]; // self-assignment on smart_reference + COMPARE(x[0], T(1)); + + std::experimental::simd + z = 2; + x[0] = z[0]; + COMPARE(x[0], T(2)); + x = 3; + z[0] = x[0]; + COMPARE(z[0], T(3)); + + // TODO: check that only value-preserving conversions happen on subscript + // assignment + } + { // not + V x = 0; + COMPARE(!x, M{true}); + V y = 1; + COMPARE(!y, M{false}); + } + + { // unary minus + V x = 0; + COMPARE(-x, V(T(-T(0)))); + V y = 1; + COMPARE(-y, V(T(-T(1)))); + } + + { // plus + V x = 0; + V y = 0; + COMPARE(x + y, x); + COMPARE(x = x + T(1), V(1)); + COMPARE(x + x, V(2)); + y = make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x = x + y, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x = x + -y, V(1)); + COMPARE(x += y, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x, make_vec({2, 3, 4, 5, 6, 7, 8})); + COMPARE(x += -y, V(1)); + COMPARE(x, V(1)); + } + + { // minus + V x = 1; + V y = 0; + COMPARE(x - y, x); + COMPARE(x - T(1), y); + COMPARE(y, x - T(1)); + COMPARE(x - x, y); + y = make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x = y - x, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(x = y - x, V(1)); + COMPARE(y -= x, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(y, make_vec({0, 1, 2, 3, 4, 5, 6})); + COMPARE(y -= y, V(0)); + COMPARE(y, V(0)); + } + + { // multiplies + V x = 1; + V y = 0; + COMPARE(x * y, y); + COMPARE(x = x * T(2), V(2)); + COMPARE(x * x, V(4)); + y = make_vec({1, 2, 3, 4, 5, 6, 7}); + COMPARE(x = x * y, make_vec({2, 4, 6, 8, 10, 12, 14})); + y = 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 = n / 2; + COMPARE(x * y, V(n)); + } + if (std::is_integral::value && std::is_unsigned::value) + { + // test modulo arithmetics + T n = max; + x = n; + for (T m : {T(2), T(7), T(max / 127), max}) + { + y = 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 + = std::conditional_t<(sizeof(T) < sizeof(int)), unsigned, T>; + COMPARE(x * y, V(T(U(n) * U(m)))); + } + } + x = 2; + COMPARE(x *= make_vec({1, 2, 3}), make_vec({2, 4, 6})); + COMPARE(x, make_vec({2, 4, 6})); + } + + // divides + constexpr bool is_iec559 = __GCC_IEC_559 >= 2; + if constexpr (std::is_floating_point_v && !is_iec559) + { // avoid testing subnormals and expect minor deltas for non-IEC559 float + V x = 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 = 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 = 2; + V ref([&](auto i) { return a[i] / 2; }); + ULP_COMPARE(a / b, ref, 1); + where(a == 0, a) = 1; + // -freciprocal-math together with flush-to-zero makes + // the following range restriction necessary (i.e. + // 1/|a| must be >= min). Intel vrcpps and vrcp14ps + // need some extra slack (use 1.1 instead of 1). + where(abs(a) >= T(1.1) / norm_min, a) = 1; + ULP_COMPARE(a / a, V(1), 1) << "\na = " << a; + ref = V([&](auto i) { return 2 / a[i]; }); + ULP_COMPARE(b / a, ref, 1) << "\na = " << a; + ULP_COMPARE(b /= a, ref, 1); + ULP_COMPARE(b, ref, 1); + }); + } + else + { + V x = 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 = 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 = make_vec({max, norm_min}); + V ref = make_vec({T(max / 2), T(norm_min / 2)}); + COMPARE(y / x, ref); + + y = make_vec({norm_min, max}); + ref = make_vec({T(norm_min / 2), T(max / 2)}); + COMPARE(y / x, ref); + + y = make_vec({max, T(norm_min + 1)}); + COMPARE(y / y, V(1)); + + ref = make_vec({T(2 / max), T(2 / (norm_min + 1))}); + COMPARE(x / y, ref); + COMPARE(x /= y, ref); + COMPARE(x, ref); + } + + { // increment & decrement + const V from0 = make_vec({0, 1, 2, 3}, 4); + V x = 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..6f4ba40133f --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" +#include + +template + void + test() + { + using T = typename V::value_type; + COMPARE(reduce(V(1)), T(V::size())); + { + V x = 1; + COMPARE(reduce(x, std::multiplies<>()), T(1)); + x[0] = 2; + COMPARE(reduce(x, std::multiplies<>()), T(2)); + if constexpr (V::size() > 1) + { + x[V::size() - 1] = 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 <= std::__finite_max_v) + { + COMPARE(reduce(V([](int i) { return i + 1; })), + T((1 + V::size()) * V::size() / 2)); + } + + { + const V y = 2; + COMPARE(reduce(y), T(2 * V::size())); + COMPARE(reduce(where(y > 2, y)), T(0)); + COMPARE(reduce(where(y == 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() == 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 /= 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 = abs(x); + T acc = x[0]; + for (size_t i = 1; i < V::size(); ++i) + acc += x[i]; + ULP_COMPARE(reduce(x), acc, V::size() / 2).on_failure("x = ", x); + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc new file mode 100644 index 00000000000..bdbacc6ef8e --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc @@ -0,0 +1,70 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(0); + vir::test::setFuzzyness(0); + + using T = 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 == 0, b) = 1; +#endif + using IV = std::experimental::fixed_size_simd; + IV quo = {}; + const V totest = remquo(a, b, &quo); + auto&& expected + = [&](const auto& v, const auto& w) -> std::pair { + std::pair tmp = {}; + using std::remquo; + for (std::size_t i = 0; i < V::size(); ++i) + { + int tmp2; + tmp.first[i] = remquo(v[i], w[i], &tmp2); + tmp.second[i] = tmp2; + } + return tmp; + }; + const auto expect1 = expected(a, b); + COMPARE(isnan(totest), isnan(expect1.first)) + << "remquo(" << a << ", " << b << ", quo) = " << totest + << " != " << expect1.first; + const V clean_a = iif(isnan(totest), 0, a); + const V clean_b = iif(isnan(totest), 1, b); + const auto expect2 = expected(clean_a, clean_b); + COMPARE(remquo(clean_a, clean_b, &quo), expect2.first) + << "\nclean_a/b = " << clean_a << ", " << clean_b; + COMPARE(quo, expect2.second); + }); + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc new file mode 100644 index 00000000000..657646c0ac5 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc @@ -0,0 +1,46 @@ +// Copyright (C) 2020 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" + +template + void + test() + { + using T = typename V::value_type; + + // V must store V::size() values of type T giving us the lower bound on the + // sizeof + VERIFY(sizeof(V) >= 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 = sizeof(T) * V::size(); + if (n & (n - 1)) + { + n = ((n << 1) & ~n) & ~((n >> 1) | (n >> 3)); + while (n & (n - 1)) + n &= n - 1; + } + if constexpr ( + !std::is_same_v>) + n *= 2; + VERIFY(sizeof(V) <= n) << "\nsizeof(V): " << sizeof(V) << "\nn: " << n; + } diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc new file mode 100644 index 00000000000..acef488e214 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc @@ -0,0 +1,44 @@ +// test only floattypes +// Copyright (C) 2020 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/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 = typename V::value_type; + + vir::test::setFuzzyness(2); + vir::test::setFuzzyness(1); + + const auto& testdata = 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 = " << input; + FUZZY_COMPARE(sin(-input), -expected_sin) << " input = " << input; + FUZZY_COMPARE(cos(input), expected_cos) << " input = " << input; + FUZZY_COMPARE(cos(-input), expected_cos) << " input = " << 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..3a79a1f8e3d --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc @@ -0,0 +1,183 @@ +// Copyright (C) 2020 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/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 = typename V::value_type; + if constexpr (V::size() * 3 + <= std::experimental::simd_abi::max_fixed_size) + { + V a(0), b(1), c(2); + auto x = concat(a, b, c); + COMPARE(x.size(), a.size() * 3); + std::size_t i = 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() >= 4) + { + const V a = gen([](auto i) -> T { return i; }); + constexpr auto N0 = V::size() / 4u; + constexpr auto N1 = V::size() - 2 * N0; + using V0 = std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + using V1 = std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + { + auto x = 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 = 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 = 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 = 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 = 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 = 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 == 0) + { + const V a = gen([](auto i) -> T { return i; }); + constexpr auto N0 = V::size() / 3; + using V0 = std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + using V1 = std::experimental::simd< + T, std::experimental::simd_abi::deduce_t>; + { + auto [x, y, z] = 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 = concat(x, y, z); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + { + auto [x, y] = std::experimental::split(a); + COMPARE(x, V0([](auto i) -> T { return i; })); + COMPARE(y, V1([](auto i) -> T { return i + N0; })); + auto b = concat(x, y); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + { + auto [x, y] = 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 = concat(x, y); + COMPARE(a.size(), b.size()); + COMPARE(b, simd_cast(a)); + COMPARE(simd_cast(b), a); + } + } + + if constexpr ((V::size() & 1) == 0) + { + using std::experimental::simd; + using std::experimental::simd_abi::deduce_t; + using V0 = simd>; + using V2 = simd>; + using V3 = simd>; + + const V a = gen([](auto i) -> T { return i; }); + + std::array v2s = std::experimental::split(a); + int offset = 0; + for (V2 test : v2s) + { + COMPARE(test, V2([&](auto i) -> T { return i + offset; })); + offset += 2; + } + COMPARE(concat(v2s), simd_cast(a)); + + std::array v3s = 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/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc new file mode 100644 index 00000000000..8b61635c2a6 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc @@ -0,0 +1,38 @@ +// Copyright (C) 2020 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" + +template + void + test() + { + using M = typename V::mask_type; + using namespace std::experimental::parallelism_v2; + using T = typename V::value_type; + if constexpr (V::size() / simd_size_v * simd_size_v == V::size()) + { + M k(true); + VERIFY(all_of(k)) << k; + const auto parts = 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.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc new file mode 100644 index 00000000000..24730f1856c --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc @@ -0,0 +1,41 @@ +// test only floattypes +// Copyright (C) 2020 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/metahelpers.h" +#include "bits/test_values.h" + +template + void + test() + { + vir::test::setFuzzyness(1); + vir::test::setFuzzyness(1); + + using T = 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_floor.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc new file mode 100644 index 00000000000..e516926ae1d --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc @@ -0,0 +1,109 @@ +// test only floattypes +// Copyright (C) 2020 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/test_values.h" +#include "bits/verify.h" + +template + void + test() + { + using T = typename V::value_type; + constexpr T inf = std::__infinity_v; + constexpr T denorm_min = std::__denorm_min_v; + constexpr T norm_min = std::__norm_min_v; + constexpr T max = std::__finite_max_v; + constexpr T min = 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/libstdc++-v3/testsuite/experimental/simd/tests/where.cc new file mode 100644 index 00000000000..5e73a3b1989 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc @@ -0,0 +1,136 @@ +// Copyright (C) 2020 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 + 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 = T(); + where(true, x) = x + 1; + COMPARE(x, T(1)); + where(false, x) = x - 1; + COMPARE(x, T(1)); + where(true, x) += T(1); + COMPARE(x, T(2)); + } + +template + void + test() + { + using M = typename V::mask_type; + using T = 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 = make_mask({true, false}); + V x = 0; + where(alternating_mask, x) = indexes; + COMPARE(alternating_mask, x == indexes); + + where(!alternating_mask, x) = T(2); + COMPARE(!alternating_mask, x == T(2)) << x; + + where(!alternating_mask, x) = Convertible(); + COMPARE(!alternating_mask, x == T(4)); + + x = 0; + COMPARE(x, T(0)); + where(alternating_mask, x) += indexes; + COMPARE(alternating_mask, x == indexes); + + x = 10; + COMPARE(x, T(10)); + where(!alternating_mask, x) += T(1); + COMPARE(!alternating_mask, x == T(11)); + where(alternating_mask, x) -= Convertible(); + COMPARE(alternating_mask, x == T(6)); + constexpr bool fast_math = +#ifdef __FAST_MATH__ + true; +#else + false; +#endif + if constexpr (fast_math && std::is_floating_point_v) + where(alternating_mask, x) *= T(.5); + else + where(alternating_mask, x) /= T(2); + COMPARE(alternating_mask, x == T(3)) << "\nx = " << x; + where(alternating_mask, x) *= T(3); + COMPARE(alternating_mask, x == T(9)); + COMPARE(!alternating_mask, x == T(11)); + + x = 10; + where(alternating_mask, x)++; + COMPARE(alternating_mask, x == T(11)); + ++where(alternating_mask, x); + COMPARE(alternating_mask, x == T(12)); + where(alternating_mask, x)--; + COMPARE(alternating_mask, x == T(11)); + --where(alternating_mask, x); + --where(alternating_mask, x); + COMPARE(alternating_mask, x == T(9)); + COMPARE(alternating_mask, -where(alternating_mask, x) == T(-T(9))); + + const auto y = 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 = alternating_mask; + where(alternating_mask, test) = M(true); + COMPARE(test, alternating_mask); + where(alternating_mask, test) = M(false); + COMPARE(test, M(false)); + where(alternating_mask, test) = M(true); + COMPARE(test, alternating_mask); + }