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); + }