--- /dev/null
+#!/bin/sh
+
+# check_simd <srcdir> <builddir> <CXXFLAGS>
+# 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
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
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
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}:
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"
# To remove directories.
clean-local:
- rm -rf de fr debug parallel binaries normal*
+ rm -rf de fr debug parallel binaries normal* simd
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))
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 \
# 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.
--- /dev/null
+#!/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 <<EOF
+Usage: $0 [Options] <g++ invocation>
+
+Options:
+ -h, --help Print this message and exit.
+ -q, --quiet Only print failures.
+ -v, --verbose Print compiler and test output on failure.
+ -t <type>, --type <type>
+ The value_type to test (default: $type).
+ -a [0-9], --abi [0-9]
+ The ABI tag subset to test (default: $abi).
+ -n <name>, --name <name>
+ The name of the test (required).
+ -k, --keep-failed Keep executables of failed tests.
+ --srcdir <path> The source directory of the tests (default: $srcdir).
+ --sim <executable> Path to an executable that is prepended to the test
+ execution binary (default: the value of
+ GCC_TEST_SIMULATOR).
+ --timeout-factor <x>
+ 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 <pattern> 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
--- /dev/null
+#!/bin/sh
+
+srcdir="$(cd "${0%/*}" && pwd)"
+driver="$srcdir/driver.sh"
+srcdir="$srcdir/tests"
+sim=
+rm_logs=true
+dst=.
+testflags=
+
+usage() {
+ cat <<EOF
+Usage: $0 [Options] <g++ invocation>
+
+Options:
+ -h, --help Print this message and exit.
+ --srcdir <path> The source directory of the tests (default: $srcdir).
+ --sim <executable> Path to an executable that is prepended to the test
+ execution binary (default: none).
+ --keep-intermediate-logs
+ Keep intermediate logs.
+ --testflags <flags> Force initial TESTFLAGS contents.
+ -d <path>, --destination <path>
+ 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" <<EOF
+srcdir = ${srcdir}
+CXX = ${CXX}
+DRIVER = ${driver}
+DRIVEROPTS ?=
+
+all: simd_testsuite.sum
+
+simd_testsuite.sum: simd_testsuite.log
+ @echo "\n\t\t=== simd_testsuite \$(TESTFLAGS) Summary ===\n\n"\\
+ "# of expected passes:\t\t\$(shell grep -c '^PASS:' \$@)\n"\\
+ "# of unexpected failures:\t\$(shell grep -c '^FAIL:' \$@)\n"\\
+ "# of unsupported tests:\t\t\$(shell grep -c '^UNSUPPORTED:' \$@)"\\
+ | tee -a \$@
+
+EOF
+
+all_types() {
+ src="$1"
+ cat <<EOF
+long double
+ldouble
+double
+double
+float
+float
+EOF
+ ([ -n "$src" ] && grep -q "test only floattypes" "$src") || \
+ cat <<EOF
+long long
+llong
+unsigned long long
+ullong
+unsigned long
+ulong
+long
+long
+int
+int
+unsigned int
+uint
+short
+short
+unsigned short
+ushort
+char
+char
+signed char
+schar
+unsigned char
+uchar
+char32_t
+char32_t
+char16_t
+char16_t
+wchar_t
+wchar_t
+EOF
+}
+
+all_tests() {
+ if [ -f testsuite_files_simd ]; then
+ sed 's,^experimental/simd/tests/,,' testsuite_files_simd | while read file; do
+ echo "$srcdir/$file"
+ echo "${file%.cc}"
+ done
+ else
+ for file in ${srcdir}/*.cc; do
+ echo "$file"
+ name="${file%.cc}"
+ echo "${name##*/}"
+ done
+ fi
+}
+
+{
+ rmline=""
+ if $rm_logs; then
+ rmline="
+ @rm \$^ \$(^:log=sum)"
+ fi
+ echo -n "simd_testsuite.log:"
+ all_tests | while read file && read name; do
+ echo -n " $name.log"
+ done
+ cat <<EOF
+
+ @cat $^ > \$@
+ @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 <<EOF
+
+ @cat $^ > \$@
+ @cat \$(^:log=sum) > \$(@:log=sum)${rmline}
+
+EOF
+ done
+ all_types | while read t && read type; do
+ cat <<EOF
+%-$type.log: %-$type-0.log %-$type-1.log %-$type-2.log %-$type-3.log \
+%-$type-4.log %-$type-5.log %-$type-6.log %-$type-7.log \
+%-$type-8.log %-$type-9.log
+ @cat $^ > \$@
+ @cat \$(^:log=sum) > \$(@:log=sum)${rmline}
+
+EOF
+ for i in $(seq 0 9); do
+ cat <<EOF
+%-$type-$i.log: \$(srcdir)/%.cc
+ @\$(DRIVER) \$(DRIVEROPTS) -t "$t" -a $i -n \$* \$(CXX) \$(CXXFLAGS)
+
+EOF
+ done
+ done
+ echo 'run-%: export GCC_TEST_RUN_EXPENSIVE=yes\n'
+ all_tests | while read file && read name; do
+ echo "run-$name: $name.log"
+ all_types "$file" | while read t && read type; do
+ echo "run-$name-$type: $name-$type.log"
+ for i in $(seq 0 9); do
+ echo "run-$name-$type-$i: $name-$type-$i.log"
+ done
+ done
+ echo
+ done
+ cat <<EOF
+help:
+ @echo "use DRIVEROPTS=<options> 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 <executable> Path to an executable that is prepended to the test\n"\\
+ " execution binary (default: the value of\n"\\
+ " GCC_TEST_SIMULATOR).\n"\\
+ "--timeout-factor <x>\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 <pattern> Compile and run only tests matching the given pattern.\n"
+ @echo "use TESTFLAGS=<flags> 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 <<EOF
+
+clean:
+ rm -f -- *.sum *.log *.exe
+
+.PHONY: clean help
+
+.PRECIOUS: %.log %.sum
+EOF
+} >> "$dst"
+
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include <cmath> // abs & sqrt
+#include <cstdlib> // integer abs
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ if constexpr (std::is_signed_v<typename V::value_type>)
+ {
+ using std::abs;
+ using T = typename V::value_type;
+ test_values<V>({std::__finite_max_v<T>, std::__norm_min_v<T>,
+ -std::__norm_min_v<T>, std::__finite_min_v<T>,
+ std::__finite_min_v<T> / 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;
+ });
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+ 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});
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <array>
+
+// 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 <typename To, typename From>
+ constexpr bool
+ is_conversion_undefined_impl(From x, std::true_type)
+ {
+ return x > static_cast<long double>(std::__finite_max_v<To>)
+ || x < static_cast<long double>(std::__finite_min_v<To>);
+ }
+
+template <typename To, typename From>
+ constexpr bool
+ is_conversion_undefined_impl(From, std::false_type)
+ { return false; }
+
+template <typename To, typename From>
+ constexpr bool
+ is_conversion_undefined(From x)
+ {
+ static_assert(std::is_arithmetic<From>::value,
+ "this overload is only meant for builtin arithmetic types");
+ return is_conversion_undefined_impl<To, From>(
+ x, std::integral_constant<
+ bool, std::is_floating_point<From>::value
+ && (std::is_integral<To>::value
+ || (std::is_floating_point<To>::value
+ && sizeof(From) > sizeof(To)))>());
+ }
+
+static_assert(is_conversion_undefined<uint>(float(0x100000000LL)),
+ "testing my expectations of is_conversion_undefined");
+static_assert(!is_conversion_undefined<float>(0x100000000LL),
+ "testing my expectations of is_conversion_undefined");
+
+template <typename To, typename T, typename A>
+ inline std::experimental::simd_mask<T, A>
+ is_conversion_undefined(const std::experimental::simd<T, A>& x)
+ {
+ std::experimental::simd_mask<T, A> k = false;
+ for (std::size_t i = 0; i < x.size(); ++i)
+ k[i] = is_conversion_undefined(x[i]);
+ return k;
+ }
+
+template <class T>
+ constexpr T
+ genHalfBits()
+ { return std::__finite_max_v<T> >> (std::__digits_v<T> / 2); }
+
+template <>
+ constexpr long double
+ genHalfBits<long double>()
+ { return 0; }
+
+template <>
+ constexpr double
+ genHalfBits<double>()
+ { return 0; }
+
+template <>
+ constexpr float
+ genHalfBits<float>()
+ { return 0; }
+
+template <class U, class T, class UU>
+ constexpr U
+ avoid_ub(UU x)
+ { return is_conversion_undefined<T>(U(x)) ? U(0) : U(x); }
+
+template <class U, class T, class UU>
+ constexpr U
+ avoid_ub2(UU x)
+ { return is_conversion_undefined<U>(x) ? U(0) : avoid_ub<U, T>(x); }
+
+// conversion test input data
+template <class U, class T>
+ static const std::array<U, 53> cvt_input_data = {{
+ avoid_ub<U, T>(0xc0000080U),
+ avoid_ub<U, T>(0xc0000081U),
+ avoid_ub<U, T>(0xc0000082U),
+ avoid_ub<U, T>(0xc0000084U),
+ avoid_ub<U, T>(0xc0000088U),
+ avoid_ub<U, T>(0xc0000090U),
+ avoid_ub<U, T>(0xc00000A0U),
+ avoid_ub<U, T>(0xc00000C0U),
+ avoid_ub<U, T>(0xc000017fU),
+ avoid_ub<U, T>(0xc0000180U),
+ avoid_ub<U, T>(0x100000001LL),
+ avoid_ub<U, T>(0x100000011LL),
+ avoid_ub<U, T>(0x100000111LL),
+ avoid_ub<U, T>(0x100001111LL),
+ avoid_ub<U, T>(0x100011111LL),
+ avoid_ub<U, T>(0x100111111LL),
+ avoid_ub<U, T>(0x101111111LL),
+ avoid_ub<U, T>(-0x100000001LL),
+ avoid_ub<U, T>(-0x100000011LL),
+ avoid_ub<U, T>(-0x100000111LL),
+ avoid_ub<U, T>(-0x100001111LL),
+ avoid_ub<U, T>(-0x100011111LL),
+ avoid_ub<U, T>(-0x100111111LL),
+ avoid_ub<U, T>(-0x101111111LL),
+ avoid_ub<U, T>(std::__norm_min_v<U>),
+ avoid_ub<U, T>(std::__norm_min_v<U> + 1),
+ avoid_ub<U, T>(std::__finite_min_v<U>),
+ avoid_ub<U, T>(std::__finite_min_v<U> + 1),
+ avoid_ub<U, T>(-1),
+ avoid_ub<U, T>(-10),
+ avoid_ub<U, T>(-100),
+ avoid_ub<U, T>(-1000),
+ avoid_ub<U, T>(-10000),
+ avoid_ub<U, T>(0),
+ avoid_ub<U, T>(1),
+ avoid_ub<U, T>(genHalfBits<U>() - 1),
+ avoid_ub<U, T>(genHalfBits<U>()),
+ avoid_ub<U, T>(genHalfBits<U>() + 1),
+ avoid_ub<U, T>(std::__finite_max_v<U> - 1),
+ avoid_ub<U, T>(std::__finite_max_v<U>),
+ avoid_ub<U, T>(std::__finite_max_v<U> - 0xff),
+ avoid_ub<U, T>(std::__finite_max_v<U> - 0xff),
+ avoid_ub<U, T>(std::__finite_max_v<U> - 0x55),
+ avoid_ub<U, T>(-(std::__finite_min_v<U> + 1)),
+ avoid_ub<U, T>(-std::__finite_max_v<U>),
+ avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 6 - 1)),
+ avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 6 - 1)),
+ avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 4 - 1)),
+ avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 4 - 1)),
+ avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 2 - 1)),
+ avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 2 - 1)),
+ avoid_ub<U, T>(std::__finite_max_v<T> - 1),
+ avoid_ub<U, T>(std::__finite_max_v<T> * 0.75),
+ }};
+
+template <class T, class U>
+ struct cvt_inputs
+ {
+ static constexpr size_t
+ size()
+ { return cvt_input_data<U, T>.size(); }
+
+ U
+ operator[](size_t i) const
+ { return cvt_input_data<U, T>[i]; }
+ };
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/simd>
+
+template <class M>
+ inline M
+ make_mask(const std::initializer_list<bool> &init)
+ {
+ std::size_t i = 0;
+ M r = {};
+ for (;;)
+ {
+ for (bool x : init)
+ {
+ r[i] = x;
+ if (++i == M::size())
+ {
+ return r;
+ }
+ }
+ }
+ }
+
+template <class V>
+ inline V
+ make_vec(const std::initializer_list<typename V::value_type> &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;
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <tuple>
+#include <utility>
+#include <cstdio>
+
+template <typename T>
+ struct SincosReference
+ {
+ T x, s, c;
+
+ std::tuple<const T &, const T &, const T &>
+ as_tuple() const
+ { return std::tie(x, s, c); }
+ };
+
+template <typename T>
+ struct Reference {
+ T x, ref;
+
+ std::tuple<const T &, const T &>
+ as_tuple() const
+ { return std::tie(x, ref); }
+ };
+
+template <typename T>
+ 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 <class F>
+ struct testdatatype_for_function
+ {
+ template <class T>
+ using type = Reference<T>;
+ };
+
+template <>
+ struct testdatatype_for_function<function::sincos>
+ {
+ template <class T>
+ using type = SincosReference<T>;
+ };
+
+template <class F, class T>
+ using testdatatype_for_function_t
+ = typename testdatatype_for_function<F>::template type<T>;
+
+template<typename T>
+ struct StaticDeleter
+ {
+ const T *ptr;
+
+ StaticDeleter(const T *p)
+ : ptr(p) {}
+
+ ~StaticDeleter()
+ { delete[] ptr; }
+ };
+
+template <class F, class T>
+ inline std::string filename()
+ {
+ static_assert(std::is_floating_point<T>::value, "");
+ static const auto cache
+ = std::string("reference-") + F::str
+ + (sizeof(T) == 4 && std::__digits_v<T> == 24
+ && std::__max_exponent_v<T> == 128
+ ? "-sp"
+ : (sizeof(T) == 8
+ && std::__digits_v<T> == 53
+ && std::__max_exponent_v<T> == 1024
+ ? "-dp"
+ : (sizeof(T) == 16 && std::__digits_v<T> == 64
+ && std::__max_exponent_v<T> == 16384
+ ? "-ep"
+ : (sizeof(T) == 16 && std::__digits_v<T> == 113
+ && std::__max_exponent_v<T> == 16384
+ ? "-qp"
+ : "-unknown"))))
+ + ".dat";
+ return cache;
+ }
+
+template <class Fun, class T, class Ref = testdatatype_for_function_t<Fun, T>>
+ Array<Ref>
+ referenceData()
+ {
+ static Array<Ref> data;
+ if (data.data_ == nullptr)
+ {
+ FILE* file = std::fopen(filename<Fun, T>().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<Ref> _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<Fun, T>().c_str());
+ __builtin_abort();
+ }
+ }
+ return data;
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef VC_TESTS_METAHELPERS_H_
+#define VC_TESTS_METAHELPERS_H_
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace vir
+{
+ namespace test
+ {
+ template <class A, class B, class Op>
+ constexpr bool
+ operator_is_substitution_failure_impl(float)
+ { return true; }
+
+ template <class A, class B, class Op>
+ constexpr typename std::conditional<true, bool, decltype(
+ Op()(std::declval<A>(), std::declval<B>()))>::type
+ operator_is_substitution_failure_impl(int)
+ { return false; }
+
+ template <class... Ts>
+ constexpr bool
+ operator_is_substitution_failure()
+ { return operator_is_substitution_failure_impl<Ts...>(int()); }
+
+ template <class... Args, class F>
+ constexpr auto
+ sfinae_is_callable_impl(int, F &&f) -> typename std::conditional<
+ true, std::true_type,
+ decltype(std::forward<F>(f)(std::declval<Args>()...))>::type;
+
+ template <class... Args, class F>
+ constexpr std::false_type
+ sfinae_is_callable_impl(float, const F &);
+
+ template <class... Args, class F>
+ constexpr bool
+ sfinae_is_callable(F &&)
+ {
+ return decltype(
+ sfinae_is_callable_impl<Args...>(int(), std::declval<F>()))::value;
+ }
+
+ template <class... Args, class F>
+ constexpr auto sfinae_is_callable_t(F &&f)
+ -> decltype(sfinae_is_callable_impl<Args...>(int(), std::declval<F>()));
+
+ template <class A, class B>
+ constexpr bool
+ has_less_bits()
+ { return std::__digits_v<A> < std::__digits_v<B>; }
+
+ } // namespace test
+} // namespace vir
+
+struct assignment
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() = std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) = std::forward<B>(b)))
+ { return std::forward<A>(a) = std::forward<B>(b); }
+};
+
+struct bit_shift_left
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() << std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) << std::forward<B>(b)))
+ { return std::forward<A>(a) << std::forward<B>(b); }
+};
+
+struct bit_shift_right
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() >> std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) >> std::forward<B>(b)))
+ { return std::forward<A>(a) >> std::forward<B>(b); }
+};
+
+struct assign_modulus
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() %= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) %= std::forward<B>(b)))
+ { return std::forward<A>(a) %= std::forward<B>(b); }
+};
+
+struct assign_bit_and
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() &= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) &= std::forward<B>(b)))
+ { return std::forward<A>(a) &= std::forward<B>(b); }
+};
+
+struct assign_bit_or
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() |= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) |= std::forward<B>(b)))
+ { return std::forward<A>(a) |= std::forward<B>(b); }
+};
+
+struct assign_bit_xor
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() ^= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) ^= std::forward<B>(b)))
+ { return std::forward<A>(a) ^= std::forward<B>(b); }
+};
+
+struct assign_bit_shift_left
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() <<= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) <<= std::forward<B>(b)))
+ { return std::forward<A>(a) <<= std::forward<B>(b); }
+};
+
+struct assign_bit_shift_right
+{
+ template <class A, class B>
+ constexpr decltype(std::declval<A>() >>= std::declval<B>())
+ operator()(A &&a, B &&b) const noexcept(noexcept(
+ std::forward<A>(a) >>= std::forward<B>(b)))
+ { return std::forward<A>(a) >>= std::forward<B>(b); }
+};
+
+template <class A, class B, class Op = std::plus<>>
+ constexpr bool is_substitution_failure
+ = vir::test::operator_is_substitution_failure<A, B, Op>();
+
+using vir::test::sfinae_is_callable;
+
+using vir::test::has_less_bits;
+
+#endif // VC_TESTS_METAHELPERS_H_
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef VC_TESTS_SIMD_VIEW_H_
+#define VC_TESTS_SIMD_VIEW_H_
+
+#include <experimental/simd>
+
+_GLIBCXX_SIMD_BEGIN_NAMESPACE
+
+namespace experimental
+{
+ namespace imported_begin_end
+ {
+ using std::begin;
+ using std::end;
+
+ template <class T>
+ using begin_type = decltype(begin(std::declval<T>()));
+
+ template <class T>
+ using end_type = decltype(end(std::declval<T>()));
+ } // namespace imported_begin_end
+
+ template <class V, class It, class End>
+ class viewer
+ {
+ It it;
+ const End end;
+
+ template <class F>
+ 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 <class F>
+ 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 <class F>
+ void
+ for_each(F &&fun)
+ {
+ constexpr size_t N
+ = std::tuple_size<std::decay_t<decltype(it->as_tuple())>>::value;
+ for_each_impl(std::forward<F>(fun), std::make_index_sequence<N>());
+ }
+ };
+
+ template <class V, class Cont>
+ viewer<V, imported_begin_end::begin_type<const Cont &>,
+ imported_begin_end::end_type<const Cont &>>
+ 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_
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/simd>
+#include <initializer_list>
+#include <random>
+#include <cfenv>
+
+template <class T, class A>
+ std::experimental::simd<T, A>
+ iif(std::experimental::simd_mask<T, A> k,
+ const typename std::experimental::simd_mask<T, A>::simd_type& t,
+ const std::experimental::simd<T, A>& f)
+ {
+ auto r = f;
+ where(k, r) = t;
+ return r;
+ }
+
+template <class V>
+ 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 <class V, class... F>
+ void
+ test_values(const std::initializer_list<typename V::value_type>& 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<V>(inputs.begin(), inputs.size())), 0)...);
+ }
+
+template <class V>
+ struct RandomValues
+ {
+ using T = typename V::value_type;
+ static constexpr bool isfp = std::is_floating_point_v<T>;
+ const std::size_t count;
+
+ std::conditional_t<std::is_floating_point_v<T>,
+ std::uniform_real_distribution<T>,
+ std::uniform_int_distribution<T>>
+ dist;
+
+ const bool uniform;
+
+ const T abs_max = std::__finite_max_v<T>;
+
+ RandomValues(std::size_t count_, T min, T max)
+ : count(count_), dist(min, max), uniform(true)
+ {
+ if constexpr (std::is_floating_point_v<T>)
+ VERIFY(max - min <= std::__finite_max_v<T>);
+ }
+
+ RandomValues(std::size_t count_)
+ : count(count_), dist(isfp ? 1 : std::__finite_min_v<T>,
+ isfp ? 2 : std::__finite_max_v<T>),
+ 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 <typename URBG>
+ 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<float>(0.f,
+ std::__max_exponent_v<T> * .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<T>);
+ fp = gen() & 0x4 ? fp : -fp;
+ return fp;
+ });
+ }
+ }
+ };
+
+static std::mt19937 g_mt_gen{0};
+
+template <class V, class... F>
+ void
+ test_values(const std::initializer_list<typename V::value_type>& inputs,
+ RandomValues<V> random, F&&... fun_pack)
+ {
+ test_values<V>(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 <class V, class... F>
+ void
+ test_values_2arg(const std::initializer_list<typename V::value_type>& 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<V>(inputs.begin(), inputs.size()),
+ V(*scalar_it)),
+ 0)...);
+ }
+ }
+
+template <class V, class... F>
+ void
+ test_values_2arg(const std::initializer_list<typename V::value_type>& inputs,
+ RandomValues<V> random, F&&... fun_pack)
+ {
+ test_values_2arg<V>(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 <class V, class... F>
+ void
+ test_values_3arg(const std::initializer_list<typename V::value_type>& 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<V>(inputs.begin(), inputs.size()),
+ V(*scalar_it1), V(*scalar_it2)),
+ 0)...);
+ }
+ }
+ }
+
+template <class V, class... F>
+ void
+ test_values_3arg(const std::initializer_list<typename V::value_type>& inputs,
+ RandomValues<V> random, F&&... fun_pack)
+ {
+ test_values_3arg<V>(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 <class V>
+ 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<T>, V>;
+ const I abs_x = __bit_cast<I>(abs(x));
+ const I min = __bit_cast<I>(V(std::__norm_min_v<T>));
+ const I max = __bit_cast<I>(V(std::__finite_max_v<T>));
+ return static_simd_cast<typename V::mask_type>(
+ __bit_cast<I>(x) == 0 || (abs_x >= min && abs_x <= max));
+ }
+ else
+ {
+ const V abs_x = abs(x);
+ const V min = std::__norm_min_v<T>;
+ // 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<T>;
+ 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<decltype(totest)>; \
+ 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<typename R::value_type>) \
+ { \
+ ((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<decltype(name_(inputs...))>; \
+ 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<typename R::value_type>) \
+ { \
+ ((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<decltype(totest)>; \
+ 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<typename R::value_type>) \
+ { \
+ ((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<decltype(totest)>; \
+ 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<typename R::value_type>) \
+ { \
+ ((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_)
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef ULP_H
+#define ULP_H
+
+#include <cmath>
+#include <experimental/simd>
+#include <type_traits>
+#include <cfenv>
+
+namespace vir {
+ namespace test {
+ template <typename T, typename R = typename T::value_type>
+ R
+ value_type_impl(int);
+
+ template <typename T>
+ T
+ value_type_impl(float);
+
+ template <typename T>
+ using value_type_t = decltype(value_type_impl<T>(int()));
+
+ template <typename T>
+ inline T
+ ulp_distance(const T& val_, const T& ref_)
+ {
+ if constexpr (std::is_floating_point_v<value_type_t<T>>)
+ {
+ 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<T>;
+
+ where(ref == 0, val) = abs(val);
+ where(ref == 0, diff) = 1;
+ where(ref == 0, ref) = std::__norm_min_v<TT>;
+ 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<TT>;
+
+ using I = decltype(fpclassify(std::declval<T>()));
+ 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<TT>));
+ diff += ldexp(abs(ref - val), std::__digits_v<TT> - 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 <typename T>
+ 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
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef TESTS_BITS_VERIFY_H_
+#define TESTS_BITS_VERIFY_H_
+
+#include <experimental/simd>
+#include <sstream>
+#include <iomanip>
+#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 <class T>
+ T
+ make_value_unknown(const T& x)
+ {
+ if constexpr (std::is_constructible_v<T, const volatile T&>)
+ {
+ const volatile T& y = x;
+ return y;
+ }
+ else
+ {
+ T y = x;
+ asm("" : "+m"(y));
+ return y;
+ }
+ }
+
+class verify
+{
+ const bool m_failed = false;
+
+ template <typename T,
+ typename = decltype(std::declval<std::stringstream&>()
+ << std::declval<const T&>())>
+ void
+ print(const T& x, int) const
+ {
+ std::stringstream ss;
+ ss << x;
+ __builtin_fprintf(stderr, "%s", ss.str().c_str());
+ }
+
+ template <typename T>
+ void
+ print(const T& x, ...) const
+ {
+ if constexpr (std::experimental::is_simd_v<T>)
+ {
+ std::stringstream ss;
+ if constexpr (std::is_floating_point_v<typename T::value_type>)
+ {
+ 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<T>)
+ {
+ __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<const unsigned char*>(x);
+ for (std::size_t i = 0; i < n; ++i)
+ {
+ __builtin_fprintf(stderr, (i && i % 4 == 0) ? "'%02x" : "%02x",
+ bytes[i]);
+ }
+ }
+
+public:
+ template <typename... Ts>
+ 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 <typename T>
+ const verify&
+ operator<<(const T& x) const
+ {
+ if (m_failed)
+ {
+ print(x, int());
+ }
+ return *this;
+ }
+
+ template <typename... Ts>
+ 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 <typename T>
+ [[gnu::always_inline]] inline decltype(auto)
+ force_fp_truncation(const T& x)
+ {
+ namespace stdx = std::experimental;
+ if constexpr (stdx::is_simd_v<T>)
+ {
+ using U = typename T::value_type;
+ if constexpr (std::is_floating_point_v<typename T::value_type>
+ && sizeof(U) <= 8 && (sizeof(T) < 16 || std::is_same_v<
+ T, stdx::fixed_size_simd<U, T::size()>>))
+ {
+ T y = x;
+ asm("" : "+m"(y));
+ return y;
+ }
+ else
+ return x;
+ }
+ else if constexpr (std::is_floating_point_v<T> && 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 <typename T>
+ inline T _S_fuzzyness = 0;
+
+ template <typename T>
+ void
+ setFuzzyness(T x)
+ { _S_fuzzyness<T> = x; }
+ } // namespace test
+} // namespace vir
+
+#define FUZZY_COMPARE(_a, _b) \
+ ULP_COMPARE( \
+ _a, _b, \
+ vir::test::_S_fuzzyness<vir::test::value_type_t<decltype((_a) + (_b))>>)
+
+template <typename V>
+ void
+ test();
+
+template <typename V>
+ void
+ invoke_test(...)
+ {}
+
+template <typename V, typename = decltype(V())>
+ void
+ invoke_test(int)
+ {
+ test<V>();
+ __builtin_fprintf(stderr, "PASS: %s\n", __PRETTY_FUNCTION__);
+ }
+
+template <class T>
+ void
+ iterate_abis()
+ {
+ using namespace std::experimental::parallelism_v2;
+#ifndef EXTENDEDTESTS
+ invoke_test<simd<T, simd_abi::scalar>>(int());
+ invoke_test<simd<T, simd_abi::_VecBuiltin<16>>>(int());
+ invoke_test<simd<T, simd_abi::_VecBltnBtmsk<64>>>(int());
+#elif EXTENDEDTESTS == 0
+ invoke_test<simd<T, simd_abi::_VecBuiltin<8>>>(int());
+ invoke_test<simd<T, simd_abi::_VecBuiltin<12>>>(int());
+ invoke_test<simd<T, simd_abi::_VecBuiltin<24>>>(int());
+ invoke_test<simd<T, simd_abi::_VecBuiltin<32>>>(int());
+ invoke_test<simd<T, simd_abi::_VecBltnBtmsk<56>>>(int());
+#elif EXTENDEDTESTS == 1
+ invoke_test<simd<T, simd_abi::fixed_size<8>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<16>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<24>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<32>>>(int());
+#elif EXTENDEDTESTS == 2
+ invoke_test<simd<T, simd_abi::fixed_size<1>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<9>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<17>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<25>>>(int());
+#elif EXTENDEDTESTS == 3
+ invoke_test<simd<T, simd_abi::fixed_size<2>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<10>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<18>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<26>>>(int());
+#elif EXTENDEDTESTS == 4
+ invoke_test<simd<T, simd_abi::fixed_size<3>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<19>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<11>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<27>>>(int());
+#elif EXTENDEDTESTS == 5
+ invoke_test<simd<T, simd_abi::fixed_size<4>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<12>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<20>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<28>>>(int());
+#elif EXTENDEDTESTS == 6
+ invoke_test<simd<T, simd_abi::fixed_size<5>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<13>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<21>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<29>>>(int());
+#elif EXTENDEDTESTS == 7
+ invoke_test<simd<T, simd_abi::fixed_size<6>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<14>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<22>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<30>>>(int());
+#elif EXTENDEDTESTS == 8
+ invoke_test<simd<T, simd_abi::fixed_size<7>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<15>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<23>>>(int());
+ invoke_test<simd<T, simd_abi::fixed_size<31>>>(int());
+#endif
+ }
+
+int main()
+{
+ iterate_abis<_GLIBCXX_SIMD_TESTTYPE>();
+ return 0;
+}
+
+#endif // TESTS_BITS_VERIFY_H_
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+enum unscoped_enum
+{ foo };
+
+enum class scoped_enum
+{ bar };
+
+struct convertible
+{
+ operator int();
+ operator float();
+};
+
+template <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+ VERIFY(std::experimental::is_simd_v<V>);
+ VERIFY(std::experimental::is_abi_tag_v<typename V::abi_type>);
+
+ {
+ 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<V&, unscoped_enum, assignment>) );
+ VERIFY((is_substitution_failure<V&, scoped_enum, assignment>) );
+ COMPARE((is_substitution_failure<V&, convertible, assignment>),
+ (!std::is_convertible<convertible, T>::value));
+ COMPARE((is_substitution_failure<V&, long double, assignment>),
+ (sizeof(long double) > sizeof(T) || std::is_integral<T>::value));
+ COMPARE((is_substitution_failure<V&, double, assignment>),
+ (sizeof(double) > sizeof(T) || std::is_integral<T>::value));
+ COMPARE((is_substitution_failure<V&, float, assignment>),
+ (sizeof(float) > sizeof(T) || std::is_integral<T>::value));
+ COMPARE((is_substitution_failure<V&, long long, assignment>),
+ (has_less_bits<T, long long>() || std::is_unsigned<T>::value));
+ COMPARE((is_substitution_failure<V&, unsigned long long, assignment>),
+ (has_less_bits<T, unsigned long long>()));
+ COMPARE((is_substitution_failure<V&, long, assignment>),
+ (has_less_bits<T, long>() || std::is_unsigned<T>::value));
+ COMPARE((is_substitution_failure<V&, unsigned long, assignment>),
+ (has_less_bits<T, unsigned long>()));
+ // int broadcast *always* works:
+ VERIFY(!(is_substitution_failure<V&, int, assignment>) );
+ // uint broadcast works for any unsigned T:
+ COMPARE((is_substitution_failure<V&, unsigned int, assignment>),
+ (!std::is_unsigned<T>::value && has_less_bits<T, unsigned int>()));
+ COMPARE((is_substitution_failure<V&, short, assignment>),
+ (has_less_bits<T, short>() || std::is_unsigned<T>::value));
+ COMPARE((is_substitution_failure<V&, unsigned short, assignment>),
+ (has_less_bits<T, unsigned short>()));
+ COMPARE((is_substitution_failure<V&, signed char, assignment>),
+ (has_less_bits<T, signed char>() || std::is_unsigned<T>::value));
+ COMPARE((is_substitution_failure<V&, unsigned char, assignment>),
+ (has_less_bits<T, unsigned char>()));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+using std::experimental::static_simd_cast;
+
+template <class T, size_t N>
+ struct gen_cast
+ {
+ std::array<T, N> data;
+
+ template <class V>
+ gen_cast(const V& v)
+ {
+ for (size_t i = 0; i < V::size(); ++i)
+ {
+ data[i] = static_cast<T>(v[i]);
+ }
+ }
+
+ template <class I>
+ constexpr T
+ operator()(I)
+ { return data[I::value]; }
+ };
+
+template <class V, class To>
+ struct gen_seq_t
+ {
+ using From = typename V::value_type;
+ const size_t N = cvt_input_data<From, To>.size();
+ size_t offset = 0;
+
+ constexpr void
+ operator++()
+ { offset += V::size(); }
+
+ explicit constexpr operator bool() const
+ { return offset < N; }
+
+ template <class I>
+ constexpr From
+ operator()(I) const
+ {
+ size_t i = I::value + offset;
+ return i < N ? cvt_input_data<From, To>[i] : From(i);
+ }
+ };
+
+template <class To>
+ struct foo
+ {
+ template <class T>
+ auto
+ operator()(const T& v) -> decltype(simd_cast<To>(v));
+ };
+
+template <typename V, typename To>
+ void
+ casts()
+ {
+ using From = typename V::value_type;
+ constexpr auto N = V::size();
+ if constexpr (N <= std::experimental::simd_abi::max_fixed_size<To>)
+ {
+ using W = std::experimental::fixed_size_simd<To, N>;
+
+ if constexpr (std::is_integral_v<From>)
+ {
+ using A = typename V::abi_type;
+ using TU = std::make_unsigned_t<From>;
+ using TS = std::make_signed_t<From>;
+ COMPARE(typeid(static_simd_cast<TU>(V())),
+ typeid(std::experimental::simd<TU, A>));
+ COMPARE(typeid(static_simd_cast<TS>(V())),
+ typeid(std::experimental::simd<TS, A>));
+ }
+
+ using is_simd_cast_allowed
+ = decltype(vir::test::sfinae_is_callable_t<const V&>(foo<To>()));
+
+ COMPARE(is_simd_cast_allowed::value,
+ std::__digits<From>::value <= std::__digits<To>::value
+ && std::__finite_max<From>::value
+ <= std::__finite_max<To>::value
+ && !(std::is_signed<From>::value
+ && std::is_unsigned<To>::value));
+
+ if constexpr (is_simd_cast_allowed::value)
+ {
+ for (gen_seq_t<V, To> gen_seq; gen_seq; ++gen_seq)
+ {
+ const V seq(gen_seq);
+ COMPARE(simd_cast<V>(seq), seq);
+ COMPARE(simd_cast<W>(seq), W(gen_cast<To, N>(seq)))
+ << "seq = " << seq;
+ auto test = simd_cast<To>(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<To, N>(seq)));
+ if (std::is_same<To, From>::value)
+ {
+ COMPARE(typeid(decltype(test)), typeid(V));
+ }
+ }
+ }
+
+ for (gen_seq_t<V, To> gen_seq; gen_seq; ++gen_seq)
+ {
+ const V seq(gen_seq);
+ COMPARE(static_simd_cast<V>(seq), seq);
+ COMPARE(static_simd_cast<W>(seq), W(gen_cast<To, N>(seq))) << '\n'
+ << seq;
+ auto test = static_simd_cast<To>(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<To, N>(seq)));
+ if (std::is_same<To, From>::value)
+ {
+ COMPARE(typeid(decltype(test)), typeid(V));
+ }
+ }
+ }
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ casts<V, long double>();
+ casts<V, double>();
+ casts<V, float>();
+ casts<V, long long>();
+ casts<V, unsigned long long>();
+ casts<V, unsigned long>();
+ casts<V, long>();
+ casts<V, int>();
+ casts<V, unsigned int>();
+ casts<V, short>();
+ casts<V, unsigned short>();
+ casts<V, char>();
+ casts<V, signed char>();
+ casts<V, unsigned char>();
+ casts<V, char32_t>();
+ casts<V, char16_t>();
+ casts<V, wchar_t>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <cfenv>
+
+template <typename F>
+ 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 <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+ using intv = std::experimental::fixed_size_simd<int, V::size()>;
+ constexpr T inf = std::__infinity_v<T>;
+ constexpr T denorm_min = std::__infinity_v<T>;
+ constexpr T nan = std::__quiet_NaN_v<T>;
+ constexpr T max = std::__finite_max_v<T>;
+ constexpr T norm_min = std::__norm_min_v<T>;
+ test_values<V>(
+ {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<T>;
+ 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
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ using int_v = std::experimental::fixed_size_simd<int, V::size()>;
+ using T = typename V::value_type;
+ constexpr auto denorm_min = std::__denorm_min_v<T>;
+ constexpr auto norm_min = std::__norm_min_v<T>;
+ constexpr auto max = std::__finite_max_v<T>;
+ constexpr auto nan = std::__quiet_NaN_v<T>;
+ constexpr auto inf = std::__infinity_v<T>;
+ test_values<V>(
+ {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<V>(
+ // 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
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <class V>
+ struct call_generator
+ {
+ template <class F>
+ auto
+ operator()(const F& f) -> decltype(V(f));
+ };
+
+using schar = signed char;
+using uchar = unsigned char;
+using ullong = unsigned long long;
+
+template <typename V>
+ 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<int (&)(int)>(call_generator<V>())));
+ COMPARE(sfinae_is_callable<schar (&)(int)>(call_generator<V>()),
+ std::is_signed<T>::value);
+ COMPARE(sfinae_is_callable<uchar (&)(int)>(call_generator<V>()),
+ !(std::is_signed_v<T> && sizeof(T) <= sizeof(uchar)));
+ COMPARE(sfinae_is_callable<float (&)(int)>(call_generator<V>()),
+ (std::is_floating_point<T>::value));
+
+ COMPARE(sfinae_is_callable<ullong (&)(int)>(call_generator<V>()),
+ std::__finite_max_v<T> >= std::__finite_max_v<ullong>
+ && std::__digits_v<T> >= std::__digits_v<ullong>);
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#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 <typename T>
+ [[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<T>;
+ else if (std::isnan(x) || std::isnan(y) || std::isnan(z))
+ return std::__quiet_NaN_v<T>;
+ 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 <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(1);
+ vir::test::setFuzzyness<double>(1);
+ vir::test::setFuzzyness<long double>(2); // because of the bad reference
+
+ using T = typename V::value_type;
+ test_values_3arg<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>,
+ std::__infinity_v<T>,
+ -std::__infinity_v<T>,
+ std::__norm_min_v<T> / 3,
+ -0.,
+ std::__denorm_min_v<T>,
+#endif
+ 0.,
+ 1.,
+ -1.,
+ std::__norm_min_v<T>,
+ -std::__norm_min_v<T>,
+ 2.,
+ -2.,
+ std::__finite_max_v<T> / 5,
+ std::__finite_max_v<T> / 3,
+ std::__finite_max_v<T> / 2,
+ -std::__finite_max_v<T> / 5,
+ -std::__finite_max_v<T> / 3,
+ -std::__finite_max_v<T> / 2,
+#ifdef __FAST_MATH__
+ // fast-math hypot is imprecise for the max exponent
+ },
+ {100000, std::__finite_max_v<T> / 2},
+#else
+ std::__finite_max_v<T>, -std::__finite_max_v<T>},
+ {100000},
+#endif
+ MAKE_TESTER_2(hypot, hypot3));
+#if !__FINITE_MATH_ONLY__
+ COMPARE(hypot(V(std::__finite_max_v<T>), V(std::__finite_max_v<T>), V()),
+ V(std::__infinity_v<T>));
+ COMPARE(hypot(V(std::__finite_max_v<T>), V(), V(std::__finite_max_v<T>)),
+ V(std::__infinity_v<T>));
+ COMPARE(hypot(V(), V(std::__finite_max_v<T>), V(std::__finite_max_v<T>)),
+ V(std::__infinity_v<T>));
+#endif
+ COMPARE(hypot(V(std::__norm_min_v<T>), V(std::__norm_min_v<T>),
+ V(std::__norm_min_v<T>)),
+ V(std::__norm_min_v<T> * std::sqrt(T(3))));
+ auto&& hypot3_test
+ = [](auto a, auto b, auto c) -> decltype(hypot(a, b, c)) { return {}; };
+ VERIFY((sfinae_is_callable<V, V, V>(hypot3_test)));
+ VERIFY((sfinae_is_callable<T, T, V>(hypot3_test)));
+ VERIFY((sfinae_is_callable<V, T, T>(hypot3_test)));
+ VERIFY((sfinae_is_callable<T, V, T>(hypot3_test)));
+ VERIFY((sfinae_is_callable<T, V, V>(hypot3_test)));
+ VERIFY((sfinae_is_callable<V, T, V>(hypot3_test)));
+ VERIFY((sfinae_is_callable<V, V, T>(hypot3_test)));
+ VERIFY((sfinae_is_callable<int, int, V>(hypot3_test)));
+ VERIFY((sfinae_is_callable<int, V, int>(hypot3_test)));
+ VERIFY((sfinae_is_callable<V, T, int>(hypot3_test)));
+ VERIFY(!(sfinae_is_callable<bool, V, V>(hypot3_test)));
+ VERIFY(!(sfinae_is_callable<V, bool, V>(hypot3_test)));
+ VERIFY(!(sfinae_is_callable<V, V, bool>(hypot3_test)));
+
+ vir::test::setFuzzyness<float>(0);
+ vir::test::setFuzzyness<double>(0);
+ test_values_3arg<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+ std::__norm_min_v<T> / 3, std::__denorm_min_v<T>,
+#endif
+ 0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+ {10000, -std::__finite_max_v<T> / 2, std::__finite_max_v<T> / 2},
+ MAKE_TESTER(fma));
+ auto&& fma_test
+ = [](auto a, auto b, auto c) -> decltype(fma(a, b, c)) { return {}; };
+ VERIFY((sfinae_is_callable<V, V, V>(fma_test)));
+ VERIFY((sfinae_is_callable<T, T, V>(fma_test)));
+ VERIFY((sfinae_is_callable<V, T, T>(fma_test)));
+ VERIFY((sfinae_is_callable<T, V, T>(fma_test)));
+ VERIFY((sfinae_is_callable<T, V, V>(fma_test)));
+ VERIFY((sfinae_is_callable<V, T, V>(fma_test)));
+ VERIFY((sfinae_is_callable<V, V, T>(fma_test)));
+ VERIFY((sfinae_is_callable<int, int, V>(fma_test)));
+ VERIFY((sfinae_is_callable<int, V, int>(fma_test)));
+ VERIFY((sfinae_is_callable<V, T, int>(fma_test)));
+ VERIFY((!sfinae_is_callable<V, T, bool>(fma_test)));
+ VERIFY((!sfinae_is_callable<bool, V, V>(fma_test)));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/metahelpers.h"
+
+template <typename T, T Begin, T End, T Stride = 1, typename F>
+ void
+ for_constexpr(F&& fun)
+ {
+ if constexpr (Begin <= End)
+ {
+ fun(std::integral_constant<T, Begin>());
+ if constexpr (Begin < End)
+ {
+ for_constexpr<T, Begin + Stride, End, Stride>(static_cast<F&&>(fun));
+ }
+ }
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+ if constexpr (std::is_integral_v<T>)
+ {
+ 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<V>({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<T>::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<V>({3, 4, 5}, 8);
+ COMPARE(x & x, x);
+ COMPARE(x & ~x, V());
+ COMPARE(x & V(), V());
+ COMPARE(V() & x, V());
+ V y = make_vec<V>({1, 5, 3}, 8);
+ COMPARE(x & y, make_vec<V>({1, 4, 1}, 8));
+ x &= y;
+ COMPARE(x, make_vec<V>({1, 4, 1}, 8));
+ }
+
+ { // bit_or
+ V x = make_vec<V>({3, 4, 5}, 8);
+ COMPARE(x | x, x);
+ COMPARE(x | ~x, ~V());
+ COMPARE(x | V(), x);
+ COMPARE(V() | x, x);
+ V y = make_vec<V>({1, 5, 3}, 8);
+ COMPARE(x | y, make_vec<V>({3, 5, 7}, 8));
+ x |= y;
+ COMPARE(x, make_vec<V>({3, 5, 7}, 8));
+ }
+
+ { // bit_xor
+ V x = make_vec<V>({3, 4, 5}, 8);
+ COMPARE(x ^ x, V());
+ COMPARE(x ^ ~x, ~V());
+ COMPARE(x ^ V(), x);
+ COMPARE(V() ^ x, x);
+ V y = make_vec<V>({1, 5, 3}, 8);
+ COMPARE(x ^ y, make_vec<V>({2, 1, 6}, 0));
+ x ^= y;
+ COMPARE(x, make_vec<V>({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<int, 0, n_promo_bits - 1>(
+ [](auto shift_ic) {
+ constexpr int shift = shift_ic;
+ const V seq = make_value_unknown(V([&](T i) {
+ if constexpr (std::is_signed_v<T>)
+ {
+ const T max = std::__finite_max_v<T> >> 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<V>({0, 1}, nbits - 2);
+ seq %= nbits - 1;
+ COMPARE(make_vec<V>({0, 1}, 0) << seq,
+ V([&](auto i) { return T(T(i & 1) << seq[i]); }))
+ << "seq = " << seq;
+ COMPARE(make_vec<V>({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<T>::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<T>::value ? std::__finite_max_v<T> : 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<int, 0, n_promo_bits - 1>([](auto shift_ic) {
+ constexpr int shift = shift_ic;
+ const V seq = make_value_unknown(V([&](int i) {
+ using U = std::make_unsigned_t<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<V, V, std::modulus<>>));
+ VERIFY((is_substitution_failure<V, V, std::bit_and<>>));
+ VERIFY((is_substitution_failure<V, V, std::bit_or<>>));
+ VERIFY((is_substitution_failure<V, V, std::bit_xor<>>));
+ VERIFY((is_substitution_failure<V, V, bit_shift_left>));
+ VERIFY((is_substitution_failure<V, V, bit_shift_right>));
+
+ VERIFY((is_substitution_failure<V&, V, assign_modulus>));
+ VERIFY((is_substitution_failure<V&, V, assign_bit_and>));
+ VERIFY((is_substitution_failure<V&, V, assign_bit_or>));
+ VERIFY((is_substitution_failure<V&, V, assign_bit_xor>));
+ VERIFY((is_substitution_failure<V&, V, assign_bit_shift_left>));
+ VERIFY((is_substitution_failure<V&, V, assign_bit_shift_right>));
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(0);
+ vir::test::setFuzzyness<double>(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<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>,
+ std::__infinity_v<T>,
+ -std::__infinity_v<T>,
+ -0.,
+ std::__denorm_min_v<T>,
+ std::__norm_min_v<T> / 3,
+ -std::__denorm_min_v<T>,
+ -std::__norm_min_v<T> / 3,
+#endif
+ +0.,
+ +1.3,
+ -1.3,
+ 2.1,
+ -2.1,
+ 0.99,
+ 0.9,
+ -0.9,
+ -0.99,
+ std::__norm_min_v<T>,
+ std::__finite_max_v<T>,
+ -std::__norm_min_v<T>,
+ -std::__finite_max_v<T>},
+ {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<decltype(totest)>;
+ 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<decltype(totest)>;
+ 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<decltype(totest)>;
+ 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<const V, const V> {
+ std::pair<V, V> 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);
+ });
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/conversions.h"
+
+template <typename V, typename U>
+ void
+ load_store()
+ {
+ // types, tags, and constants
+ using T = typename V::value_type;
+ auto&& gen = make_vec<V>;
+ 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<stride_alignment * sizeof(U)>>;
+ constexpr stride_aligned_t stride_aligned = {};
+ constexpr size_t alignment
+ = 2 * std::experimental::memory_alignment_v<V, U>;
+ constexpr auto overaligned = std::experimental::overaligned<alignment>;
+ 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<T, U> test_values;
+
+ constexpr auto mem_size
+ = test_values.size() > 3 * V::size() ? test_values.size() : 3 * V::size();
+ alignas(std::experimental::memory_alignment_v<V, U> * 2) U mem[mem_size]
+ = {};
+ alignas(std::experimental::memory_alignment_v<V, T> * 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<T>(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<T>(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<M>({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 <typename V>
+ void
+ test()
+ {
+ load_store<V, long double>();
+ load_store<V, double>();
+ load_store<V, float>();
+ load_store<V, long long>();
+ load_store<V, unsigned long long>();
+ load_store<V, unsigned long>();
+ load_store<V, long>();
+ load_store<V, int>();
+ load_store<V, unsigned int>();
+ load_store<V, short>();
+ load_store<V, unsigned short>();
+ load_store<V, char>();
+ load_store<V, signed char>();
+ load_store<V, unsigned char>();
+ load_store<V, char32_t>();
+ load_store<V, char16_t>();
+ load_store<V, wchar_t>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(1);
+ vir::test::setFuzzyness<double>(1);
+
+ using T = typename V::value_type;
+ constexpr T nan = std::__quiet_NaN_v<T>;
+ constexpr T inf = std::__infinity_v<T>;
+ constexpr T denorm_min = std::__denorm_min_v<T>;
+ constexpr T norm_min = std::__norm_min_v<T>;
+ constexpr T min = std::__finite_min_v<T>;
+ constexpr T max = std::__finite_max_v<T>;
+ test_values<V>({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));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ static_assert(std::is_convertible<typename M::reference, bool>::value,
+ "A smart_reference<simd_mask> must be convertible to bool.");
+ static_assert(
+ std::is_same<bool, decltype(std::declval<const typename M::reference&>()
+ == true)>::value,
+ "A smart_reference<simd_mask> must be comparable against bool.");
+ static_assert(
+ vir::test::sfinae_is_callable<typename M::reference&&, bool>(
+ [](auto&& a, auto&& b) -> decltype(std::declval<decltype(a)>()
+ == std::declval<decltype(b)>()) {
+ return {};
+ }),
+ "A smart_reference<simd_mask> must be comparable against bool.");
+ VERIFY(std::experimental::is_simd_mask_v<M>);
+
+ {
+ 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);
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+namespace stdx = std::experimental;
+
+template <typename From, typename To>
+ 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<To>(From());
+ COMPARE(typeid(x), typeid(To));
+ COMPARE(x, To());
+
+ x = resizing_simd_cast<To>(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<To>(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 <typename T, typename V, typename = void>
+ struct rebind_or_max_fixed
+ {
+ using type = stdx::rebind_simd_t<
+ T, stdx::resize_simd_t<stdx::simd_abi::max_fixed_size<T>, V>>;
+ };
+
+template <typename T, typename V>
+ struct rebind_or_max_fixed<T, V, std::void_t<stdx::rebind_simd_t<T, V>>>
+ {
+ using type = stdx::rebind_simd_t<T, V>;
+ };
+
+template <typename From, typename To>
+ void
+ apply_abis()
+ {
+ using M0 = typename rebind_or_max_fixed<To, From>::type;
+ using M1 = stdx::native_simd_mask<To>;
+ using M2 = stdx::simd_mask<To>;
+ using M3 = stdx::simd_mask<To, stdx::simd_abi::scalar>;
+
+ using std::is_same_v;
+ conversions<From, M0>();
+ if constexpr (!is_same_v<M1, M0>)
+ conversions<From, M1>();
+ if constexpr (!is_same_v<M2, M0> && !is_same_v<M2, M1>)
+ conversions<From, M2>();
+ if constexpr (!is_same_v<M3, M0> && !is_same_v<M3, M1> && !is_same_v<M3, M2>)
+ conversions<From, M3>();
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ apply_abis<M, ldouble>();
+ apply_abis<M, double>();
+ apply_abis<M, float>();
+ apply_abis<M, ullong>();
+ apply_abis<M, llong>();
+ apply_abis<M, ulong>();
+ apply_abis<M, long>();
+ apply_abis<M, uint>();
+ apply_abis<M, int>();
+ apply_abis<M, ushort>();
+ apply_abis<M, short>();
+ apply_abis<M, uchar>();
+ apply_abis<M, schar>();
+ apply_abis<M, char>();
+ apply_abis<M, wchar_t>();
+ apply_abis<M, char16_t>();
+ apply_abis<M, char32_t>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <class M, class M2>
+ constexpr bool assign_should_work
+ = std::is_same<M, M2>::value
+ || (std::is_same<typename M::abi_type,
+ std::experimental::simd_abi::fixed_size<M::size()>>::value
+ && std::is_same<typename M::abi_type, typename M2::abi_type>::value);
+
+template <class M, class M2>
+ constexpr bool assign_should_not_work = !assign_should_work<M, M2>;
+
+template <class L, class R>
+ std::enable_if_t<assign_should_work<L, R>>
+ 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 <class L, class R>
+ std::enable_if_t<assign_should_not_work<L, R>>
+ implicit_conversions_test()
+ {
+ VERIFY((is_substitution_failure<L&, R, assignment>) );
+ }
+
+template <typename V>
+ 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<M, simd_mask<ldouble>>();
+ implicit_conversions_test<M, simd_mask<double>>();
+ implicit_conversions_test<M, simd_mask<float>>();
+ implicit_conversions_test<M, simd_mask<ullong>>();
+ implicit_conversions_test<M, simd_mask<llong>>();
+ implicit_conversions_test<M, simd_mask<ulong>>();
+ implicit_conversions_test<M, simd_mask<long>>();
+ implicit_conversions_test<M, simd_mask<uint>>();
+ implicit_conversions_test<M, simd_mask<int>>();
+ implicit_conversions_test<M, simd_mask<ushort>>();
+ implicit_conversions_test<M, simd_mask<short>>();
+ implicit_conversions_test<M, simd_mask<uchar>>();
+ implicit_conversions_test<M, simd_mask<schar>>();
+ implicit_conversions_test<M, native_simd_mask<ldouble>>();
+ implicit_conversions_test<M, native_simd_mask<double>>();
+ implicit_conversions_test<M, native_simd_mask<float>>();
+ implicit_conversions_test<M, native_simd_mask<ullong>>();
+ implicit_conversions_test<M, native_simd_mask<llong>>();
+ implicit_conversions_test<M, native_simd_mask<ulong>>();
+ implicit_conversions_test<M, native_simd_mask<long>>();
+ implicit_conversions_test<M, native_simd_mask<uint>>();
+ implicit_conversions_test<M, native_simd_mask<int>>();
+ implicit_conversions_test<M, native_simd_mask<ushort>>();
+ implicit_conversions_test<M, native_simd_mask<short>>();
+ implicit_conversions_test<M, native_simd_mask<uchar>>();
+ implicit_conversions_test<M, native_simd_mask<schar>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<ldouble, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<double, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<float, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<ullong, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<llong, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<ulong, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<long, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<uint, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<int, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<ushort, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<short, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<uchar, M::size()>>();
+ implicit_conversions_test<M, fixed_size_simd_mask<schar, M::size()>>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+// simd_mask generator functions
+template <class M>
+ M
+ make_mask(const std::initializer_list<bool>& init)
+ {
+ std::size_t i = 0;
+ M r = {};
+ for (;;)
+ {
+ for (bool x : init)
+ {
+ r[i] = x;
+ if (++i == M::size())
+ {
+ return r;
+ }
+ }
+ }
+ }
+
+template <class M>
+ M
+ make_alternating_mask()
+ {
+ return make_mask<M>({false, true});
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ // loads
+ constexpr size_t alignment = 2 * std::experimental::memory_alignment_v<M>;
+ 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<stride_alignment * sizeof(bool)>>;
+ constexpr stride_aligned_t stride_aligned = {};
+ constexpr auto overaligned = std::experimental::overaligned<alignment>;
+
+ const M alternating_mask = make_alternating_mask<M>();
+
+ 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);
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#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 <typename M0, typename M1>
+ constexpr bool
+ bit_and_is_illformed()
+ {
+ return is_substitution_failure<M0, M1, std::bit_and<>>;
+ }
+
+template <typename M0, typename M1>
+ void
+ test_binary_op_cvt()
+ {
+ COMPARE((bit_and_is_illformed<M0, M1>()), !(std::is_same_v<M0, M1>) );
+ }
+
+template <typename V>
+ 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<M, bool>();
+
+ test_binary_op_cvt<M, simd_mask<ldouble>>();
+ test_binary_op_cvt<M, simd_mask<double>>();
+ test_binary_op_cvt<M, simd_mask<float>>();
+ test_binary_op_cvt<M, simd_mask<ullong>>();
+ test_binary_op_cvt<M, simd_mask<llong>>();
+ test_binary_op_cvt<M, simd_mask<ulong>>();
+ test_binary_op_cvt<M, simd_mask<long>>();
+ test_binary_op_cvt<M, simd_mask<uint>>();
+ test_binary_op_cvt<M, simd_mask<int>>();
+ test_binary_op_cvt<M, simd_mask<ushort>>();
+ test_binary_op_cvt<M, simd_mask<short>>();
+ test_binary_op_cvt<M, simd_mask<uchar>>();
+ test_binary_op_cvt<M, simd_mask<schar>>();
+ test_binary_op_cvt<M, simd_mask<wchar>>();
+ test_binary_op_cvt<M, simd_mask<char16>>();
+ test_binary_op_cvt<M, simd_mask<char32>>();
+
+ test_binary_op_cvt<M, native_simd_mask<ldouble>>();
+ test_binary_op_cvt<M, native_simd_mask<double>>();
+ test_binary_op_cvt<M, native_simd_mask<float>>();
+ test_binary_op_cvt<M, native_simd_mask<ullong>>();
+ test_binary_op_cvt<M, native_simd_mask<llong>>();
+ test_binary_op_cvt<M, native_simd_mask<ulong>>();
+ test_binary_op_cvt<M, native_simd_mask<long>>();
+ test_binary_op_cvt<M, native_simd_mask<uint>>();
+ test_binary_op_cvt<M, native_simd_mask<int>>();
+ test_binary_op_cvt<M, native_simd_mask<ushort>>();
+ test_binary_op_cvt<M, native_simd_mask<short>>();
+ test_binary_op_cvt<M, native_simd_mask<uchar>>();
+ test_binary_op_cvt<M, native_simd_mask<schar>>();
+ test_binary_op_cvt<M, native_simd_mask<wchar>>();
+ test_binary_op_cvt<M, native_simd_mask<char16>>();
+ test_binary_op_cvt<M, native_simd_mask<char32>>();
+
+ test_binary_op_cvt<M, fixed_size_simd_mask<ldouble, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<double, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<float, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<ullong, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<llong, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<ulong, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<long, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<uint, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<int, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<ushort, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<short, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<uchar, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<schar, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<wchar, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<char16, 2>>();
+ test_binary_op_cvt<M, fixed_size_simd_mask<char32, 2>>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+ 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);
+ }
+ }
+
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// simd_mask generator functions
+template <class M>
+ M
+ make_mask(const std::initializer_list<bool>& init)
+ {
+ std::size_t i = 0;
+ M r = {};
+ for (;;)
+ {
+ for (bool x : init)
+ {
+ r[i] = x;
+ if (++i == M::size())
+ {
+ return r;
+ }
+ }
+ }
+ }
+
+template <class M>
+ M
+ make_alternating_mask()
+ {
+ return make_mask<M>({false, true});
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ const M alternating_mask = make_alternating_mask<M>();
+ COMPARE(alternating_mask[0], false); // assumption below
+ auto&& gen = make_mask<M>;
+
+ // 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<bool>(
+ [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::find_first_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::find_first_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::find_first_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](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<bool>(
+ [](auto x) -> decltype(std::experimental::find_last_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<int>(
+ [](auto x) -> decltype(std::experimental::find_last_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<float>(
+ [](auto x) -> decltype(std::experimental::find_last_set(x)) {
+ return {};
+ }));
+ VERIFY(!sfinae_is_callable<char>(
+ [](auto x) -> decltype(std::experimental::find_last_set(x)) {
+ return {};
+ }));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(0);
+ vir::test::setFuzzyness<double>(0);
+
+ using T = typename V::value_type;
+ constexpr T inf = std::__infinity_v<T>;
+ constexpr T nan = std::__quiet_NaN_v<T>;
+ constexpr T denorm_min = std::__denorm_min_v<T>;
+ constexpr T norm_min = std::__norm_min_v<T>;
+ constexpr T max = std::__finite_max_v<T>;
+#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<T>;
+ const T before_one = (2 - std::__epsilon_v<T>) / 2;
+#else
+ constexpr T after_one = 1 + std::__epsilon_v<T>;
+ constexpr T before_one = (2 - std::__epsilon_v<T>) / 2;
+#endif
+ const std::initializer_list<T>
+ 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<V>(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<float>(1);
+ vir::test::setFuzzyness<double>(0);
+#elif __FLT_EVAL_METHOD__ == 2
+ vir::test::setFuzzyness<float>(1);
+ vir::test::setFuzzyness<double>(1);
+#endif
+ test_values<V>(input_values, {10000}, MAKE_TESTER(sqrt));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+
+ vir::test::setFuzzyness<float>(1);
+ vir::test::setFuzzyness<double>(1);
+ vir::test::setFuzzyness<long double>(1);
+ test_values_2arg<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+ std::__denorm_min_v<T>, std::__norm_min_v<T> / 3,
+#endif
+ +0., std::__norm_min_v<T>, 1., 2., std::__finite_max_v<T> / 5,
+ std::__finite_max_v<T> / 3, std::__finite_max_v<T> / 2,
+#ifdef __FAST_MATH__
+ // fast-math hypot is imprecise for the max exponent
+ },
+ {100000, std::__finite_max_v<T> / 2},
+#else
+ std::__finite_max_v<T>},
+ {100000},
+#endif
+ MAKE_TESTER(hypot));
+#if !__FINITE_MATH_ONLY__
+ COMPARE(hypot(V(std::__finite_max_v<T>), V(std::__finite_max_v<T>)),
+ V(std::__infinity_v<T>));
+#endif
+ COMPARE(hypot(V(std::__norm_min_v<T>), V(std::__norm_min_v<T>)),
+ V(std::__norm_min_v<T> * std::sqrt(T(2))));
+ VERIFY((sfinae_is_callable<V, V>(
+ [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+ VERIFY((sfinae_is_callable<typename V::value_type, V>(
+ [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+ VERIFY((sfinae_is_callable<V, typename V::value_type>(
+ [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+
+ vir::test::setFuzzyness<float>(0);
+ vir::test::setFuzzyness<double>(0);
+ vir::test::setFuzzyness<long double>(0);
+ test_values_2arg<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>,
+ std::__denorm_min_v<T>, std::__norm_min_v<T> / 3, -0.,
+#endif
+ +0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+ {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));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// type with sizeof(char) but different signedness
+using xchar = std::conditional_t<std::is_unsigned_v<char>, schar, uchar>;
+
+using vschar = std::experimental::native_simd<schar>;
+using vuchar = std::experimental::native_simd<uchar>;
+using vshort = std::experimental::native_simd<short>;
+using vushort = std::experimental::native_simd<ushort>;
+using vint = std::experimental::native_simd<int>;
+using vuint = std::experimental::native_simd<uint>;
+using vlong = std::experimental::native_simd<long>;
+using vulong = std::experimental::native_simd<ulong>;
+using vllong = std::experimental::native_simd<llong>;
+using vullong = std::experimental::native_simd<ullong>;
+using vfloat = std::experimental::native_simd<float>;
+using vdouble = std::experimental::native_simd<double>;
+using vldouble = std::experimental::native_simd<long double>;
+using vchar = std::experimental::native_simd<char>;
+using vxchar = std::experimental::native_simd<xchar>;
+
+template <typename T>
+ using vi8 = std::experimental::fixed_size_simd<T, vschar::size()>;
+template <typename T>
+ using vi16 = std::experimental::fixed_size_simd<T, vshort::size()>;
+template <typename T>
+ using vf32 = std::experimental::fixed_size_simd<T, vfloat::size()>;
+template <typename T>
+ using vi32 = std::experimental::fixed_size_simd<T, vint::size()>;
+template <typename T>
+ using vf64 = std::experimental::fixed_size_simd<T, vdouble::size()>;
+template <typename T>
+ using vi64 = std::experimental::fixed_size_simd<T, vllong::size()>;
+template <typename T>
+ using vl = typename std::conditional<sizeof(long) == sizeof(llong), vi64<T>,
+ vi32<T>>::type;
+
+template <class A, class B, class Expected = A>
+ void
+ binary_op_return_type()
+ {
+ using namespace vir::test;
+ static_assert(std::is_same<A, Expected>::value, "");
+ using AC = std::add_const_t<A>;
+ using BC = std::add_const_t<B>;
+ 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 <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+ namespace simd_abi = std::experimental::simd_abi;
+ binary_op_return_type<V, V, V>();
+ binary_op_return_type<V, T, V>();
+ binary_op_return_type<V, int, V>();
+
+ if constexpr (std::is_same_v<V, vfloat>)
+ {
+ binary_op_return_type<vfloat, schar>();
+ binary_op_return_type<vfloat, uchar>();
+ binary_op_return_type<vfloat, short>();
+ binary_op_return_type<vfloat, ushort>();
+
+ binary_op_return_type<vf32<float>, schar>();
+ binary_op_return_type<vf32<float>, uchar>();
+ binary_op_return_type<vf32<float>, short>();
+ binary_op_return_type<vf32<float>, ushort>();
+ binary_op_return_type<vf32<float>, int>();
+ binary_op_return_type<vf32<float>, float>();
+
+ binary_op_return_type<vf32<float>, vf32<schar>>();
+ binary_op_return_type<vf32<float>, vf32<uchar>>();
+ binary_op_return_type<vf32<float>, vf32<short>>();
+ binary_op_return_type<vf32<float>, vf32<ushort>>();
+ binary_op_return_type<vf32<float>, vf32<float>>();
+
+ VERIFY((is_substitution_failure<vfloat, uint>));
+ VERIFY((is_substitution_failure<vfloat, long>));
+ VERIFY((is_substitution_failure<vfloat, ulong>));
+ VERIFY((is_substitution_failure<vfloat, llong>));
+ VERIFY((is_substitution_failure<vfloat, ullong>));
+ VERIFY((is_substitution_failure<vfloat, double>));
+ VERIFY((is_substitution_failure<vfloat, vf32<schar>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<uchar>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<short>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<ushort>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<int>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<uint>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<long>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<ulong>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<llong>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<ullong>>));
+ VERIFY((is_substitution_failure<vfloat, vf32<float>>));
+
+ VERIFY((is_substitution_failure<vf32<float>, vfloat>));
+ VERIFY((is_substitution_failure<vf32<float>, uint>));
+ VERIFY((is_substitution_failure<vf32<float>, long>));
+ VERIFY((is_substitution_failure<vf32<float>, ulong>));
+ VERIFY((is_substitution_failure<vf32<float>, llong>));
+ VERIFY((is_substitution_failure<vf32<float>, ullong>));
+ VERIFY((is_substitution_failure<vf32<float>, double>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<int>>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<uint>>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<long>>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<ulong>>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<llong>>));
+ VERIFY((is_substitution_failure<vf32<float>, vf32<ullong>>));
+
+ VERIFY((is_substitution_failure<vfloat, vf32<double>>));
+ }
+ else if constexpr (std::is_same_v<V, vdouble>)
+ {
+ binary_op_return_type<vdouble, float, vdouble>();
+ binary_op_return_type<vdouble, schar>();
+ binary_op_return_type<vdouble, uchar>();
+ binary_op_return_type<vdouble, short>();
+ binary_op_return_type<vdouble, ushort>();
+ binary_op_return_type<vdouble, uint>();
+
+ binary_op_return_type<vf64<double>, schar>();
+ binary_op_return_type<vf64<double>, uchar>();
+ binary_op_return_type<vf64<double>, short>();
+ binary_op_return_type<vf64<double>, ushort>();
+ binary_op_return_type<vf64<double>, uint>();
+ binary_op_return_type<vf64<double>, int, vf64<double>>();
+ binary_op_return_type<vf64<double>, float, vf64<double>>();
+ binary_op_return_type<vf64<double>, double, vf64<double>>();
+ binary_op_return_type<vf64<double>, vf64<double>, vf64<double>>();
+ binary_op_return_type<vf32<double>, schar>();
+ binary_op_return_type<vf32<double>, uchar>();
+ binary_op_return_type<vf32<double>, short>();
+ binary_op_return_type<vf32<double>, ushort>();
+ binary_op_return_type<vf32<double>, uint>();
+ binary_op_return_type<vf32<double>, int, vf32<double>>();
+ binary_op_return_type<vf32<double>, float, vf32<double>>();
+ binary_op_return_type<vf32<double>, double, vf32<double>>();
+ binary_op_return_type<vf64<double>, vf64<schar>>();
+ binary_op_return_type<vf64<double>, vf64<uchar>>();
+ binary_op_return_type<vf64<double>, vf64<short>>();
+ binary_op_return_type<vf64<double>, vf64<ushort>>();
+ binary_op_return_type<vf64<double>, vf64<int>>();
+ binary_op_return_type<vf64<double>, vf64<uint>>();
+ binary_op_return_type<vf64<double>, vf64<float>>();
+
+ VERIFY((is_substitution_failure<vdouble, llong>));
+ VERIFY((is_substitution_failure<vdouble, ullong>));
+ VERIFY((is_substitution_failure<vdouble, vf64<schar>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<uchar>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<short>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<ushort>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<int>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<uint>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<long>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<ulong>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<llong>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<ullong>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<float>>));
+ VERIFY((is_substitution_failure<vdouble, vf64<double>>));
+
+ VERIFY((is_substitution_failure<vf64<double>, vdouble>));
+ VERIFY((is_substitution_failure<vf64<double>, llong>));
+ VERIFY((is_substitution_failure<vf64<double>, ullong>));
+ VERIFY((is_substitution_failure<vf64<double>, vf64<llong>>));
+ VERIFY((is_substitution_failure<vf64<double>, vf64<ullong>>));
+
+ VERIFY((is_substitution_failure<vf32<double>, llong>));
+ VERIFY((is_substitution_failure<vf32<double>, ullong>));
+
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ VERIFY((is_substitution_failure<vdouble, long>));
+ VERIFY((is_substitution_failure<vdouble, ulong>));
+ VERIFY((is_substitution_failure<vf64<double>, long>));
+ VERIFY((is_substitution_failure<vf64<double>, ulong>));
+ VERIFY((is_substitution_failure<vf64<double>, vf64<long>>));
+ VERIFY((is_substitution_failure<vf64<double>, vf64<ulong>>));
+ VERIFY((is_substitution_failure<vf32<double>, long>));
+ VERIFY((is_substitution_failure<vf32<double>, ulong>));
+ }
+ else
+ {
+ binary_op_return_type<vdouble, long>();
+ binary_op_return_type<vdouble, ulong>();
+ binary_op_return_type<vf64<double>, long>();
+ binary_op_return_type<vf64<double>, ulong>();
+ binary_op_return_type<vf64<double>, vf64<long>>();
+ binary_op_return_type<vf64<double>, vf64<ulong>>();
+ binary_op_return_type<vf32<double>, long>();
+ binary_op_return_type<vf32<double>, ulong>();
+ }
+ }
+ else if constexpr (std::is_same_v<V, vldouble>)
+ {
+ binary_op_return_type<vldouble, schar>();
+ binary_op_return_type<vldouble, uchar>();
+ binary_op_return_type<vldouble, short>();
+ binary_op_return_type<vldouble, ushort>();
+ binary_op_return_type<vldouble, uint>();
+ binary_op_return_type<vldouble, long>();
+ binary_op_return_type<vldouble, ulong>();
+ binary_op_return_type<vldouble, float>();
+ binary_op_return_type<vldouble, double>();
+
+ binary_op_return_type<vf64<long double>, schar>();
+ binary_op_return_type<vf64<long double>, uchar>();
+ binary_op_return_type<vf64<long double>, short>();
+ binary_op_return_type<vf64<long double>, ushort>();
+ binary_op_return_type<vf64<long double>, int>();
+ binary_op_return_type<vf64<long double>, uint>();
+ binary_op_return_type<vf64<long double>, long>();
+ binary_op_return_type<vf64<long double>, ulong>();
+ binary_op_return_type<vf64<long double>, float>();
+ binary_op_return_type<vf64<long double>, double>();
+ binary_op_return_type<vf64<long double>, vf64<long double>>();
+
+ using std::experimental::simd;
+ using A = simd_abi::fixed_size<vldouble::size()>;
+ binary_op_return_type<simd<long double, A>, schar>();
+ binary_op_return_type<simd<long double, A>, uchar>();
+ binary_op_return_type<simd<long double, A>, short>();
+ binary_op_return_type<simd<long double, A>, ushort>();
+ binary_op_return_type<simd<long double, A>, int>();
+ binary_op_return_type<simd<long double, A>, uint>();
+ binary_op_return_type<simd<long double, A>, long>();
+ binary_op_return_type<simd<long double, A>, ulong>();
+ binary_op_return_type<simd<long double, A>, float>();
+ binary_op_return_type<simd<long double, A>, double>();
+
+ if constexpr (sizeof(ldouble) == sizeof(double))
+ {
+ VERIFY((is_substitution_failure<vldouble, llong>));
+ VERIFY((is_substitution_failure<vldouble, ullong>));
+ VERIFY((is_substitution_failure<vf64<ldouble>, llong>));
+ VERIFY((is_substitution_failure<vf64<ldouble>, ullong>));
+ VERIFY((is_substitution_failure<simd<ldouble, A>, llong>));
+ VERIFY((is_substitution_failure<simd<ldouble, A>, ullong>));
+ }
+ else
+ {
+ binary_op_return_type<vldouble, llong>();
+ binary_op_return_type<vldouble, ullong>();
+ binary_op_return_type<vf64<long double>, llong>();
+ binary_op_return_type<vf64<long double>, ullong>();
+ binary_op_return_type<simd<long double, A>, llong>();
+ binary_op_return_type<simd<long double, A>, ullong>();
+ }
+
+ VERIFY((is_substitution_failure<vf64<long double>, vldouble>));
+ COMPARE((is_substitution_failure<simd<long double, A>, vldouble>),
+ (!std::is_same<A, vldouble::abi_type>::value));
+ }
+ else if constexpr (std::is_same_v<V, vlong>)
+ {
+ VERIFY((is_substitution_failure<vi32<long>, double>));
+ VERIFY((is_substitution_failure<vi32<long>, float>));
+ VERIFY((is_substitution_failure<vi32<long>, vi32<float>>));
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ binary_op_return_type<vlong, uint>();
+ binary_op_return_type<vlong, llong>();
+ binary_op_return_type<vi32<long>, uint>();
+ binary_op_return_type<vi32<long>, llong>();
+ binary_op_return_type<vi64<long>, uint>();
+ binary_op_return_type<vi64<long>, llong>();
+ binary_op_return_type<vi32<long>, vi32<uint>>();
+ binary_op_return_type<vi64<long>, vi64<uint>>();
+ VERIFY((is_substitution_failure<vi32<long>, vi32<double>>));
+ VERIFY((is_substitution_failure<vi64<long>, vi64<double>>));
+ }
+ else
+ {
+ VERIFY((is_substitution_failure<vlong, uint>));
+ VERIFY((is_substitution_failure<vlong, llong>));
+ VERIFY((is_substitution_failure<vi32<long>, uint>));
+ VERIFY((is_substitution_failure<vi32<long>, llong>));
+ VERIFY((is_substitution_failure<vi64<long>, uint>));
+ VERIFY((is_substitution_failure<vi64<long>, llong>));
+ VERIFY((is_substitution_failure<vi32<long>, vi32<uint>>));
+ VERIFY((is_substitution_failure<vi64<long>, vi64<uint>>));
+ binary_op_return_type<vi32<double>, vi32<long>>();
+ binary_op_return_type<vi64<double>, vi64<long>>();
+ }
+
+ binary_op_return_type<vlong, schar, vlong>();
+ binary_op_return_type<vlong, uchar, vlong>();
+ binary_op_return_type<vlong, short, vlong>();
+ binary_op_return_type<vlong, ushort, vlong>();
+
+ binary_op_return_type<vi32<long>, schar, vi32<long>>();
+ binary_op_return_type<vi32<long>, uchar, vi32<long>>();
+ binary_op_return_type<vi32<long>, short, vi32<long>>();
+ binary_op_return_type<vi32<long>, ushort, vi32<long>>();
+ binary_op_return_type<vi32<long>, int, vi32<long>>();
+ binary_op_return_type<vi32<long>, long, vi32<long>>();
+ binary_op_return_type<vi32<long>, vi32<long>, vi32<long>>();
+ binary_op_return_type<vi64<long>, schar, vi64<long>>();
+ binary_op_return_type<vi64<long>, uchar, vi64<long>>();
+ binary_op_return_type<vi64<long>, short, vi64<long>>();
+ binary_op_return_type<vi64<long>, ushort, vi64<long>>();
+ binary_op_return_type<vi64<long>, int, vi64<long>>();
+ binary_op_return_type<vi64<long>, long, vi64<long>>();
+ binary_op_return_type<vi64<long>, vi64<long>, vi64<long>>();
+
+ VERIFY((is_substitution_failure<vlong, vulong>));
+ VERIFY((is_substitution_failure<vlong, ulong>));
+ VERIFY((is_substitution_failure<vlong, ullong>));
+ VERIFY((is_substitution_failure<vlong, float>));
+ VERIFY((is_substitution_failure<vlong, double>));
+ VERIFY((is_substitution_failure<vlong, vl<schar>>));
+ VERIFY((is_substitution_failure<vlong, vl<uchar>>));
+ VERIFY((is_substitution_failure<vlong, vl<short>>));
+ VERIFY((is_substitution_failure<vlong, vl<ushort>>));
+ VERIFY((is_substitution_failure<vlong, vl<int>>));
+ VERIFY((is_substitution_failure<vlong, vl<uint>>));
+ VERIFY((is_substitution_failure<vlong, vl<long>>));
+ VERIFY((is_substitution_failure<vlong, vl<ulong>>));
+ VERIFY((is_substitution_failure<vlong, vl<llong>>));
+ VERIFY((is_substitution_failure<vlong, vl<ullong>>));
+ VERIFY((is_substitution_failure<vlong, vl<float>>));
+ VERIFY((is_substitution_failure<vlong, vl<double>>));
+ VERIFY((is_substitution_failure<vl<long>, vlong>));
+ VERIFY((is_substitution_failure<vl<long>, vulong>));
+ VERIFY((is_substitution_failure<vi32<long>, ulong>));
+ VERIFY((is_substitution_failure<vi32<long>, ullong>));
+ binary_op_return_type<vi32<long>, vi32<schar>>();
+ binary_op_return_type<vi32<long>, vi32<uchar>>();
+ binary_op_return_type<vi32<long>, vi32<short>>();
+ binary_op_return_type<vi32<long>, vi32<ushort>>();
+ binary_op_return_type<vi32<long>, vi32<int>>();
+ VERIFY((is_substitution_failure<vi32<long>, vi32<ulong>>));
+ VERIFY((is_substitution_failure<vi32<long>, vi32<ullong>>));
+ VERIFY((is_substitution_failure<vi64<long>, ulong>));
+ VERIFY((is_substitution_failure<vi64<long>, ullong>));
+ VERIFY((is_substitution_failure<vi64<long>, float>));
+ VERIFY((is_substitution_failure<vi64<long>, double>));
+ binary_op_return_type<vi64<long>, vi64<schar>>();
+ binary_op_return_type<vi64<long>, vi64<uchar>>();
+ binary_op_return_type<vi64<long>, vi64<short>>();
+ binary_op_return_type<vi64<long>, vi64<ushort>>();
+ binary_op_return_type<vi64<long>, vi64<int>>();
+ VERIFY((is_substitution_failure<vi64<long>, vi64<ulong>>));
+ VERIFY((is_substitution_failure<vi64<long>, vi64<ullong>>));
+ VERIFY((is_substitution_failure<vi64<long>, vi64<float>>));
+
+ binary_op_return_type<vi32<llong>, vi32<long>>();
+ binary_op_return_type<vi64<llong>, vi64<long>>();
+ }
+ else if constexpr (std::is_same_v<V, vulong>)
+ {
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ binary_op_return_type<vulong, ullong, vulong>();
+ binary_op_return_type<vi32<ulong>, ullong, vi32<ulong>>();
+ binary_op_return_type<vi64<ulong>, ullong, vi64<ulong>>();
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<llong>>));
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<double>>));
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<llong>>));
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<double>>));
+ }
+ else
+ {
+ VERIFY((is_substitution_failure<vulong, ullong>));
+ VERIFY((is_substitution_failure<vi32<ulong>, ullong>));
+ VERIFY((is_substitution_failure<vi64<ulong>, ullong>));
+ binary_op_return_type<vi32<llong>, vi32<ulong>>();
+ binary_op_return_type<vi32<double>, vi32<ulong>>();
+ binary_op_return_type<vi64<llong>, vi64<ulong>>();
+ binary_op_return_type<vi64<double>, vi64<ulong>>();
+ }
+
+ binary_op_return_type<vulong, uchar, vulong>();
+ binary_op_return_type<vulong, ushort, vulong>();
+ binary_op_return_type<vulong, uint, vulong>();
+ binary_op_return_type<vi32<ulong>, uchar, vi32<ulong>>();
+ binary_op_return_type<vi32<ulong>, ushort, vi32<ulong>>();
+ binary_op_return_type<vi32<ulong>, int, vi32<ulong>>();
+ binary_op_return_type<vi32<ulong>, uint, vi32<ulong>>();
+ binary_op_return_type<vi32<ulong>, ulong, vi32<ulong>>();
+ binary_op_return_type<vi32<ulong>, vi32<ulong>, vi32<ulong>>();
+ binary_op_return_type<vi64<ulong>, uchar, vi64<ulong>>();
+ binary_op_return_type<vi64<ulong>, ushort, vi64<ulong>>();
+ binary_op_return_type<vi64<ulong>, int, vi64<ulong>>();
+ binary_op_return_type<vi64<ulong>, uint, vi64<ulong>>();
+ binary_op_return_type<vi64<ulong>, ulong, vi64<ulong>>();
+ binary_op_return_type<vi64<ulong>, vi64<ulong>, vi64<ulong>>();
+
+ VERIFY((is_substitution_failure<vi32<ulong>, llong>));
+ VERIFY((is_substitution_failure<vi32<ulong>, float>));
+ VERIFY((is_substitution_failure<vi32<ulong>, double>));
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<float>>));
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<float>>));
+ VERIFY((is_substitution_failure<vulong, schar>));
+ VERIFY((is_substitution_failure<vulong, short>));
+ VERIFY((is_substitution_failure<vulong, vlong>));
+ VERIFY((is_substitution_failure<vulong, long>));
+ VERIFY((is_substitution_failure<vulong, llong>));
+ VERIFY((is_substitution_failure<vulong, float>));
+ VERIFY((is_substitution_failure<vulong, double>));
+ VERIFY((is_substitution_failure<vulong, vl<schar>>));
+ VERIFY((is_substitution_failure<vulong, vl<uchar>>));
+ VERIFY((is_substitution_failure<vulong, vl<short>>));
+ VERIFY((is_substitution_failure<vulong, vl<ushort>>));
+ VERIFY((is_substitution_failure<vulong, vl<int>>));
+ VERIFY((is_substitution_failure<vulong, vl<uint>>));
+ VERIFY((is_substitution_failure<vulong, vl<long>>));
+ VERIFY((is_substitution_failure<vulong, vl<ulong>>));
+ VERIFY((is_substitution_failure<vulong, vl<llong>>));
+ VERIFY((is_substitution_failure<vulong, vl<ullong>>));
+ VERIFY((is_substitution_failure<vulong, vl<float>>));
+ VERIFY((is_substitution_failure<vulong, vl<double>>));
+ VERIFY((is_substitution_failure<vl<ulong>, vlong>));
+ VERIFY((is_substitution_failure<vl<ulong>, vulong>));
+ VERIFY((is_substitution_failure<vi32<ulong>, schar>));
+ VERIFY((is_substitution_failure<vi32<ulong>, short>));
+ VERIFY((is_substitution_failure<vi32<ulong>, long>));
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<schar>>));
+ binary_op_return_type<vi32<ulong>, vi32<uchar>>();
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<short>>));
+ binary_op_return_type<vi32<ulong>, vi32<ushort>>();
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<int>>));
+ binary_op_return_type<vi32<ulong>, vi32<uint>>();
+ VERIFY((is_substitution_failure<vi32<ulong>, vi32<long>>));
+ binary_op_return_type<vi32<ullong>, vi32<ulong>>();
+ VERIFY((is_substitution_failure<vi64<ulong>, schar>));
+ VERIFY((is_substitution_failure<vi64<ulong>, short>));
+ VERIFY((is_substitution_failure<vi64<ulong>, long>));
+ VERIFY((is_substitution_failure<vi64<ulong>, llong>));
+ VERIFY((is_substitution_failure<vi64<ulong>, float>));
+ VERIFY((is_substitution_failure<vi64<ulong>, double>));
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<schar>>));
+ binary_op_return_type<vi64<ulong>, vi64<uchar>>();
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<short>>));
+ binary_op_return_type<vi64<ulong>, vi64<ushort>>();
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<int>>));
+ binary_op_return_type<vi64<ulong>, vi64<uint>>();
+ VERIFY((is_substitution_failure<vi64<ulong>, vi64<long>>));
+ binary_op_return_type<vi64<ullong>, vi64<ulong>>();
+ }
+ else if constexpr (std::is_same_v<V, vllong>)
+ {
+ binary_op_return_type<vllong, schar, vllong>();
+ binary_op_return_type<vllong, uchar, vllong>();
+ binary_op_return_type<vllong, short, vllong>();
+ binary_op_return_type<vllong, ushort, vllong>();
+ binary_op_return_type<vllong, uint, vllong>();
+ binary_op_return_type<vllong, long, vllong>();
+ binary_op_return_type<vi32<llong>, schar, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, uchar, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, short, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, ushort, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, int, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, uint, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, long, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, llong, vi32<llong>>();
+ binary_op_return_type<vi32<llong>, vi32<llong>, vi32<llong>>();
+ binary_op_return_type<vi64<llong>, schar, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, uchar, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, short, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, ushort, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, int, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, uint, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, long, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, llong, vi64<llong>>();
+ binary_op_return_type<vi64<llong>, vi64<llong>>();
+ binary_op_return_type<vi32<llong>, vi32<schar>>();
+ binary_op_return_type<vi32<llong>, vi32<uchar>>();
+ binary_op_return_type<vi32<llong>, vi32<short>>();
+ binary_op_return_type<vi32<llong>, vi32<ushort>>();
+ binary_op_return_type<vi32<llong>, vi32<int>>();
+ binary_op_return_type<vi32<llong>, vi32<uint>>();
+ binary_op_return_type<vi32<llong>, vi32<long>>();
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ VERIFY((is_substitution_failure<vi32<llong>, vi32<ulong>>));
+ VERIFY((is_substitution_failure<vi32<llong>, ulong>));
+ VERIFY((is_substitution_failure<vi64<llong>, ulong>));
+ VERIFY((is_substitution_failure<vllong, ulong>));
+ }
+ else
+ {
+ binary_op_return_type<vi32<llong>, vi32<ulong>>();
+ binary_op_return_type<vi32<llong>, ulong>();
+ binary_op_return_type<vi64<llong>, ulong>();
+ binary_op_return_type<vllong, ulong>();
+ }
+
+ VERIFY((is_substitution_failure<vllong, vullong>));
+ VERIFY((is_substitution_failure<vllong, ullong>));
+ VERIFY((is_substitution_failure<vllong, float>));
+ VERIFY((is_substitution_failure<vllong, double>));
+ VERIFY((is_substitution_failure<vllong, vi64<schar>>));
+ VERIFY((is_substitution_failure<vllong, vi64<uchar>>));
+ VERIFY((is_substitution_failure<vllong, vi64<short>>));
+ VERIFY((is_substitution_failure<vllong, vi64<ushort>>));
+ VERIFY((is_substitution_failure<vllong, vi64<int>>));
+ VERIFY((is_substitution_failure<vllong, vi64<uint>>));
+ VERIFY((is_substitution_failure<vllong, vi64<long>>));
+ VERIFY((is_substitution_failure<vllong, vi64<ulong>>));
+ VERIFY((is_substitution_failure<vllong, vi64<llong>>));
+ VERIFY((is_substitution_failure<vllong, vi64<ullong>>));
+ VERIFY((is_substitution_failure<vllong, vi64<float>>));
+ VERIFY((is_substitution_failure<vllong, vi64<double>>));
+ VERIFY((is_substitution_failure<vi32<llong>, ullong>));
+ VERIFY((is_substitution_failure<vi32<llong>, float>));
+ VERIFY((is_substitution_failure<vi32<llong>, double>));
+ VERIFY((is_substitution_failure<vi32<llong>, vi32<ullong>>));
+ VERIFY((is_substitution_failure<vi32<llong>, vi32<float>>));
+ VERIFY((is_substitution_failure<vi32<llong>, vi32<double>>));
+ VERIFY((is_substitution_failure<vi64<llong>, vllong>));
+ VERIFY((is_substitution_failure<vi64<llong>, vullong>));
+ VERIFY((is_substitution_failure<vi64<llong>, ullong>));
+ VERIFY((is_substitution_failure<vi64<llong>, float>));
+ VERIFY((is_substitution_failure<vi64<llong>, double>));
+ binary_op_return_type<vi64<llong>, vi64<schar>>();
+ binary_op_return_type<vi64<llong>, vi64<uchar>>();
+ binary_op_return_type<vi64<llong>, vi64<short>>();
+ binary_op_return_type<vi64<llong>, vi64<ushort>>();
+ binary_op_return_type<vi64<llong>, vi64<int>>();
+ binary_op_return_type<vi64<llong>, vi64<uint>>();
+ binary_op_return_type<vi64<llong>, vi64<long>>();
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ VERIFY((is_substitution_failure<vi64<llong>, vi64<ulong>>));
+ }
+ else
+ {
+ binary_op_return_type<vi64<llong>, vi64<ulong>>();
+ }
+ VERIFY((is_substitution_failure<vi64<llong>, vi64<ullong>>));
+ VERIFY((is_substitution_failure<vi64<llong>, vi64<float>>));
+ VERIFY((is_substitution_failure<vi64<llong>, vi64<double>>));
+ }
+ else if constexpr (std::is_same_v<V, vullong>)
+ {
+ binary_op_return_type<vullong, uchar, vullong>();
+ binary_op_return_type<vullong, ushort, vullong>();
+ binary_op_return_type<vullong, uint, vullong>();
+ binary_op_return_type<vullong, ulong, vullong>();
+ binary_op_return_type<vi32<ullong>, uchar, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, ushort, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, int, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, uint, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, ulong, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, ullong, vi32<ullong>>();
+ binary_op_return_type<vi32<ullong>, vi32<ullong>, vi32<ullong>>();
+ binary_op_return_type<vi64<ullong>, uchar, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, ushort, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, int, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, uint, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, ulong, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, ullong, vi64<ullong>>();
+ binary_op_return_type<vi64<ullong>, vi64<ullong>, vi64<ullong>>();
+
+ VERIFY((is_substitution_failure<vullong, schar>));
+ VERIFY((is_substitution_failure<vullong, short>));
+ VERIFY((is_substitution_failure<vullong, long>));
+ VERIFY((is_substitution_failure<vullong, llong>));
+ VERIFY((is_substitution_failure<vullong, vllong>));
+ VERIFY((is_substitution_failure<vullong, float>));
+ VERIFY((is_substitution_failure<vullong, double>));
+ VERIFY((is_substitution_failure<vullong, vi64<schar>>));
+ VERIFY((is_substitution_failure<vullong, vi64<uchar>>));
+ VERIFY((is_substitution_failure<vullong, vi64<short>>));
+ VERIFY((is_substitution_failure<vullong, vi64<ushort>>));
+ VERIFY((is_substitution_failure<vullong, vi64<int>>));
+ VERIFY((is_substitution_failure<vullong, vi64<uint>>));
+ VERIFY((is_substitution_failure<vullong, vi64<long>>));
+ VERIFY((is_substitution_failure<vullong, vi64<ulong>>));
+ VERIFY((is_substitution_failure<vullong, vi64<llong>>));
+ VERIFY((is_substitution_failure<vullong, vi64<ullong>>));
+ VERIFY((is_substitution_failure<vullong, vi64<float>>));
+ VERIFY((is_substitution_failure<vullong, vi64<double>>));
+ VERIFY((is_substitution_failure<vi32<ullong>, schar>));
+ VERIFY((is_substitution_failure<vi32<ullong>, short>));
+ VERIFY((is_substitution_failure<vi32<ullong>, long>));
+ VERIFY((is_substitution_failure<vi32<ullong>, llong>));
+ VERIFY((is_substitution_failure<vi32<ullong>, float>));
+ VERIFY((is_substitution_failure<vi32<ullong>, double>));
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<schar>>));
+ binary_op_return_type<vi32<ullong>, vi32<uchar>>();
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<short>>));
+ binary_op_return_type<vi32<ullong>, vi32<ushort>>();
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<int>>));
+ binary_op_return_type<vi32<ullong>, vi32<uint>>();
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<long>>));
+ binary_op_return_type<vi32<ullong>, vi32<ulong>>();
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<llong>>));
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<float>>));
+ VERIFY((is_substitution_failure<vi32<ullong>, vi32<double>>));
+ VERIFY((is_substitution_failure<vi64<ullong>, schar>));
+ VERIFY((is_substitution_failure<vi64<ullong>, short>));
+ VERIFY((is_substitution_failure<vi64<ullong>, long>));
+ VERIFY((is_substitution_failure<vi64<ullong>, llong>));
+ VERIFY((is_substitution_failure<vi64<ullong>, vllong>));
+ VERIFY((is_substitution_failure<vi64<ullong>, vullong>));
+ VERIFY((is_substitution_failure<vi64<ullong>, float>));
+ VERIFY((is_substitution_failure<vi64<ullong>, double>));
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<schar>>));
+ binary_op_return_type<vi64<ullong>, vi64<uchar>>();
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<short>>));
+ binary_op_return_type<vi64<ullong>, vi64<ushort>>();
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<int>>));
+ binary_op_return_type<vi64<ullong>, vi64<uint>>();
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<long>>));
+ binary_op_return_type<vi64<ullong>, vi64<ulong>>();
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<llong>>));
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<float>>));
+ VERIFY((is_substitution_failure<vi64<ullong>, vi64<double>>));
+ }
+ else if constexpr (std::is_same_v<V, vint>)
+ {
+ binary_op_return_type<vint, schar, vint>();
+ binary_op_return_type<vint, uchar, vint>();
+ binary_op_return_type<vint, short, vint>();
+ binary_op_return_type<vint, ushort, vint>();
+ binary_op_return_type<vi32<int>, schar, vi32<int>>();
+ binary_op_return_type<vi32<int>, uchar, vi32<int>>();
+ binary_op_return_type<vi32<int>, short, vi32<int>>();
+ binary_op_return_type<vi32<int>, ushort, vi32<int>>();
+ binary_op_return_type<vi32<int>, int, vi32<int>>();
+ binary_op_return_type<vi32<int>, vi32<int>, vi32<int>>();
+ binary_op_return_type<vi32<int>, vi32<schar>>();
+ binary_op_return_type<vi32<int>, vi32<uchar>>();
+ binary_op_return_type<vi32<int>, vi32<short>>();
+ binary_op_return_type<vi32<int>, vi32<ushort>>();
+
+ binary_op_return_type<vi32<llong>, vi32<int>>();
+ binary_op_return_type<vi32<double>, vi32<int>>();
+
+ // 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<int> + llong will
+ // produce a vi32<llong> if a vi32<llong> operator test is done before the
+ // vi32<int> + llong test.
+ VERIFY((is_substitution_failure<vi32<int>, double>));
+ VERIFY((is_substitution_failure<vi32<int>, float>));
+ VERIFY((is_substitution_failure<vi32<int>, llong>));
+ VERIFY((is_substitution_failure<vi32<int>, vi32<float>>));
+ VERIFY((is_substitution_failure<vint, vuint>));
+ VERIFY((is_substitution_failure<vint, uint>));
+ VERIFY((is_substitution_failure<vint, ulong>));
+ VERIFY((is_substitution_failure<vint, llong>));
+ VERIFY((is_substitution_failure<vint, ullong>));
+ VERIFY((is_substitution_failure<vint, float>));
+ VERIFY((is_substitution_failure<vint, double>));
+ VERIFY((is_substitution_failure<vint, vi32<schar>>));
+ VERIFY((is_substitution_failure<vint, vi32<uchar>>));
+ VERIFY((is_substitution_failure<vint, vi32<short>>));
+ VERIFY((is_substitution_failure<vint, vi32<ushort>>));
+ VERIFY((is_substitution_failure<vint, vi32<int>>));
+ VERIFY((is_substitution_failure<vint, vi32<uint>>));
+ VERIFY((is_substitution_failure<vint, vi32<long>>));
+ VERIFY((is_substitution_failure<vint, vi32<ulong>>));
+ VERIFY((is_substitution_failure<vint, vi32<llong>>));
+ VERIFY((is_substitution_failure<vint, vi32<ullong>>));
+ VERIFY((is_substitution_failure<vint, vi32<float>>));
+ VERIFY((is_substitution_failure<vint, vi32<double>>));
+ VERIFY((is_substitution_failure<vi32<int>, vint>));
+ VERIFY((is_substitution_failure<vi32<int>, vuint>));
+ VERIFY((is_substitution_failure<vi32<int>, uint>));
+ VERIFY((is_substitution_failure<vi32<int>, ulong>));
+ VERIFY((is_substitution_failure<vi32<int>, ullong>));
+ VERIFY((is_substitution_failure<vi32<int>, vi32<uint>>));
+ VERIFY((is_substitution_failure<vi32<int>, vi32<ulong>>));
+ VERIFY((is_substitution_failure<vi32<int>, vi32<ullong>>));
+
+ binary_op_return_type<vi32<long>, vi32<int>>();
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ VERIFY((is_substitution_failure<vint, long>));
+ VERIFY((is_substitution_failure<vi32<int>, long>));
+ }
+ else
+ {
+ binary_op_return_type<vint, long>();
+ binary_op_return_type<vi32<int>, long>();
+ }
+ }
+ else if constexpr (std::is_same_v<V, vuint>)
+ {
+ VERIFY((is_substitution_failure<vi32<uint>, llong>));
+ VERIFY((is_substitution_failure<vi32<uint>, ullong>));
+ VERIFY((is_substitution_failure<vi32<uint>, float>));
+ VERIFY((is_substitution_failure<vi32<uint>, double>));
+ VERIFY((is_substitution_failure<vi32<uint>, vi32<float>>));
+
+ binary_op_return_type<vuint, uchar, vuint>();
+ binary_op_return_type<vuint, ushort, vuint>();
+ binary_op_return_type<vi32<uint>, uchar, vi32<uint>>();
+ binary_op_return_type<vi32<uint>, ushort, vi32<uint>>();
+ binary_op_return_type<vi32<uint>, int, vi32<uint>>();
+ binary_op_return_type<vi32<uint>, uint, vi32<uint>>();
+ binary_op_return_type<vi32<uint>, vi32<uint>, vi32<uint>>();
+ binary_op_return_type<vi32<uint>, vi32<uchar>>();
+ binary_op_return_type<vi32<uint>, vi32<ushort>>();
+
+ binary_op_return_type<vi32<llong>, vi32<uint>>();
+ binary_op_return_type<vi32<ullong>, vi32<uint>>();
+ binary_op_return_type<vi32<double>, vi32<uint>>();
+
+ VERIFY((is_substitution_failure<vuint, schar>));
+ VERIFY((is_substitution_failure<vuint, short>));
+ VERIFY((is_substitution_failure<vuint, vint>));
+ VERIFY((is_substitution_failure<vuint, long>));
+ VERIFY((is_substitution_failure<vuint, llong>));
+ VERIFY((is_substitution_failure<vuint, ullong>));
+ VERIFY((is_substitution_failure<vuint, float>));
+ VERIFY((is_substitution_failure<vuint, double>));
+ VERIFY((is_substitution_failure<vuint, vi32<schar>>));
+ VERIFY((is_substitution_failure<vuint, vi32<uchar>>));
+ VERIFY((is_substitution_failure<vuint, vi32<short>>));
+ VERIFY((is_substitution_failure<vuint, vi32<ushort>>));
+ VERIFY((is_substitution_failure<vuint, vi32<int>>));
+ VERIFY((is_substitution_failure<vuint, vi32<uint>>));
+ VERIFY((is_substitution_failure<vuint, vi32<long>>));
+ VERIFY((is_substitution_failure<vuint, vi32<ulong>>));
+ VERIFY((is_substitution_failure<vuint, vi32<llong>>));
+ VERIFY((is_substitution_failure<vuint, vi32<ullong>>));
+ VERIFY((is_substitution_failure<vuint, vi32<float>>));
+ VERIFY((is_substitution_failure<vuint, vi32<double>>));
+ VERIFY((is_substitution_failure<vi32<uint>, schar>));
+ VERIFY((is_substitution_failure<vi32<uint>, short>));
+ VERIFY((is_substitution_failure<vi32<uint>, vint>));
+ VERIFY((is_substitution_failure<vi32<uint>, vuint>));
+ VERIFY((is_substitution_failure<vi32<uint>, long>));
+ VERIFY((is_substitution_failure<vi32<uint>, vi32<schar>>));
+ VERIFY((is_substitution_failure<vi32<uint>, vi32<short>>));
+ VERIFY((is_substitution_failure<vi32<uint>, vi32<int>>));
+
+ binary_op_return_type<vi32<ulong>, vi32<uint>>();
+ if constexpr (sizeof(long) == sizeof(llong))
+ {
+ VERIFY((is_substitution_failure<vuint, ulong>));
+ VERIFY((is_substitution_failure<vi32<uint>, ulong>));
+ binary_op_return_type<vi32<long>, vi32<uint>>();
+ }
+ else
+ {
+ binary_op_return_type<vuint, ulong>();
+ binary_op_return_type<vi32<uint>, ulong>();
+ VERIFY((is_substitution_failure<vi32<uint>, vi32<long>>));
+ }
+ }
+ else if constexpr (std::is_same_v<V, vshort>)
+ {
+ binary_op_return_type<vshort, schar, vshort>();
+ binary_op_return_type<vshort, uchar, vshort>();
+ binary_op_return_type<vi16<short>, schar, vi16<short>>();
+ binary_op_return_type<vi16<short>, uchar, vi16<short>>();
+ binary_op_return_type<vi16<short>, short, vi16<short>>();
+ binary_op_return_type<vi16<short>, int, vi16<short>>();
+ binary_op_return_type<vi16<short>, vi16<schar>>();
+ binary_op_return_type<vi16<short>, vi16<uchar>>();
+ binary_op_return_type<vi16<short>, vi16<short>>();
+
+ binary_op_return_type<vi16<int>, vi16<short>>();
+ binary_op_return_type<vi16<long>, vi16<short>>();
+ binary_op_return_type<vi16<llong>, vi16<short>>();
+ binary_op_return_type<vi16<float>, vi16<short>>();
+ binary_op_return_type<vi16<double>, vi16<short>>();
+
+ VERIFY((is_substitution_failure<vi16<short>, double>));
+ VERIFY((is_substitution_failure<vi16<short>, llong>));
+ VERIFY((is_substitution_failure<vshort, vushort>));
+ VERIFY((is_substitution_failure<vshort, ushort>));
+ VERIFY((is_substitution_failure<vshort, uint>));
+ VERIFY((is_substitution_failure<vshort, long>));
+ VERIFY((is_substitution_failure<vshort, ulong>));
+ VERIFY((is_substitution_failure<vshort, llong>));
+ VERIFY((is_substitution_failure<vshort, ullong>));
+ VERIFY((is_substitution_failure<vshort, float>));
+ VERIFY((is_substitution_failure<vshort, double>));
+ VERIFY((is_substitution_failure<vshort, vi16<schar>>));
+ VERIFY((is_substitution_failure<vshort, vi16<uchar>>));
+ VERIFY((is_substitution_failure<vshort, vi16<short>>));
+ VERIFY((is_substitution_failure<vshort, vi16<ushort>>));
+ VERIFY((is_substitution_failure<vshort, vi16<int>>));
+ VERIFY((is_substitution_failure<vshort, vi16<uint>>));
+ VERIFY((is_substitution_failure<vshort, vi16<long>>));
+ VERIFY((is_substitution_failure<vshort, vi16<ulong>>));
+ VERIFY((is_substitution_failure<vshort, vi16<llong>>));
+ VERIFY((is_substitution_failure<vshort, vi16<ullong>>));
+ VERIFY((is_substitution_failure<vshort, vi16<float>>));
+ VERIFY((is_substitution_failure<vshort, vi16<double>>));
+ VERIFY((is_substitution_failure<vi16<short>, vshort>));
+ VERIFY((is_substitution_failure<vi16<short>, vushort>));
+ VERIFY((is_substitution_failure<vi16<short>, ushort>));
+ VERIFY((is_substitution_failure<vi16<short>, uint>));
+ VERIFY((is_substitution_failure<vi16<short>, long>));
+ VERIFY((is_substitution_failure<vi16<short>, ulong>));
+ VERIFY((is_substitution_failure<vi16<short>, ullong>));
+ VERIFY((is_substitution_failure<vi16<short>, float>));
+ VERIFY((is_substitution_failure<vi16<short>, vi16<ushort>>));
+ VERIFY((is_substitution_failure<vi16<short>, vi16<uint>>));
+ VERIFY((is_substitution_failure<vi16<short>, vi16<ulong>>));
+ VERIFY((is_substitution_failure<vi16<short>, vi16<ullong>>));
+ }
+ else if constexpr (std::is_same_v<V, vushort>)
+ {
+ binary_op_return_type<vushort, uchar, vushort>();
+ binary_op_return_type<vushort, uint, vushort>();
+ binary_op_return_type<vi16<ushort>, uchar, vi16<ushort>>();
+ binary_op_return_type<vi16<ushort>, ushort, vi16<ushort>>();
+ binary_op_return_type<vi16<ushort>, int, vi16<ushort>>();
+ binary_op_return_type<vi16<ushort>, uint, vi16<ushort>>();
+ binary_op_return_type<vi16<ushort>, vi16<uchar>>();
+ binary_op_return_type<vi16<ushort>, vi16<ushort>>();
+
+ binary_op_return_type<vi16<int>, vi16<ushort>>();
+ binary_op_return_type<vi16<long>, vi16<ushort>>();
+ binary_op_return_type<vi16<llong>, vi16<ushort>>();
+ binary_op_return_type<vi16<uint>, vi16<ushort>>();
+ binary_op_return_type<vi16<ulong>, vi16<ushort>>();
+ binary_op_return_type<vi16<ullong>, vi16<ushort>>();
+ binary_op_return_type<vi16<float>, vi16<ushort>>();
+ binary_op_return_type<vi16<double>, vi16<ushort>>();
+
+ VERIFY((is_substitution_failure<vi16<ushort>, llong>));
+ VERIFY((is_substitution_failure<vi16<ushort>, ullong>));
+ VERIFY((is_substitution_failure<vi16<ushort>, double>));
+ VERIFY((is_substitution_failure<vushort, schar>));
+ VERIFY((is_substitution_failure<vushort, short>));
+ VERIFY((is_substitution_failure<vushort, vshort>));
+ VERIFY((is_substitution_failure<vushort, long>));
+ VERIFY((is_substitution_failure<vushort, ulong>));
+ VERIFY((is_substitution_failure<vushort, llong>));
+ VERIFY((is_substitution_failure<vushort, ullong>));
+ VERIFY((is_substitution_failure<vushort, float>));
+ VERIFY((is_substitution_failure<vushort, double>));
+ VERIFY((is_substitution_failure<vushort, vi16<schar>>));
+ VERIFY((is_substitution_failure<vushort, vi16<uchar>>));
+ VERIFY((is_substitution_failure<vushort, vi16<short>>));
+ VERIFY((is_substitution_failure<vushort, vi16<ushort>>));
+ VERIFY((is_substitution_failure<vushort, vi16<int>>));
+ VERIFY((is_substitution_failure<vushort, vi16<uint>>));
+ VERIFY((is_substitution_failure<vushort, vi16<long>>));
+ VERIFY((is_substitution_failure<vushort, vi16<ulong>>));
+ VERIFY((is_substitution_failure<vushort, vi16<llong>>));
+ VERIFY((is_substitution_failure<vushort, vi16<ullong>>));
+ VERIFY((is_substitution_failure<vushort, vi16<float>>));
+ VERIFY((is_substitution_failure<vushort, vi16<double>>));
+ VERIFY((is_substitution_failure<vi16<ushort>, schar>));
+ VERIFY((is_substitution_failure<vi16<ushort>, short>));
+ VERIFY((is_substitution_failure<vi16<ushort>, vshort>));
+ VERIFY((is_substitution_failure<vi16<ushort>, vushort>));
+ VERIFY((is_substitution_failure<vi16<ushort>, long>));
+ VERIFY((is_substitution_failure<vi16<ushort>, ulong>));
+ VERIFY((is_substitution_failure<vi16<ushort>, float>));
+ VERIFY((is_substitution_failure<vi16<ushort>, vi16<schar>>));
+ VERIFY((is_substitution_failure<vi16<ushort>, vi16<short>>));
+ }
+ else if constexpr (std::is_same_v<V, vchar>)
+ {
+ binary_op_return_type<vi8<char>, char, vi8<char>>();
+ binary_op_return_type<vi8<char>, int, vi8<char>>();
+ binary_op_return_type<vi8<char>, vi8<char>, vi8<char>>();
+
+ if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+ {
+ VERIFY(!(is_substitution_failure<vi8<char>, vi8<short>>));
+ VERIFY(!(is_substitution_failure<vi8<char>, vi8<int>>));
+ VERIFY(!(is_substitution_failure<vi8<char>, vi8<long>>));
+ VERIFY(!(is_substitution_failure<vi8<char>, vi8<llong>>));
+ COMPARE((is_substitution_failure<vi8<char>, vi8<ushort>>),
+ std::is_signed_v<char>);
+ COMPARE((is_substitution_failure<vi8<char>, vi8<uint>>),
+ std::is_signed_v<char>);
+ COMPARE((is_substitution_failure<vi8<char>, vi8<ulong>>),
+ std::is_signed_v<char>);
+ COMPARE((is_substitution_failure<vi8<char>, vi8<ullong>>),
+ std::is_signed_v<char>);
+ if constexpr (std::is_signed_v<char>)
+ {
+ binary_op_return_type<vi8<short>, vi8<char>>();
+ binary_op_return_type<vi8<int>, vi8<char>>();
+ binary_op_return_type<vi8<long>, vi8<char>>();
+ binary_op_return_type<vi8<llong>, vi8<char>>();
+ }
+ else
+ {
+ binary_op_return_type<vi8<ushort>, vi8<char>>();
+ binary_op_return_type<vi8<uint>, vi8<char>>();
+ binary_op_return_type<vi8<ulong>, vi8<char>>();
+ binary_op_return_type<vi8<ullong>, vi8<char>>();
+ }
+ binary_op_return_type<vi8<float>, vi8<char>>();
+ binary_op_return_type<vi8<double>, vi8<char>>();
+ }
+
+ VERIFY((is_substitution_failure<vi8<char>, llong>));
+ VERIFY((is_substitution_failure<vi8<char>, double>));
+ VERIFY((is_substitution_failure<vchar, vxchar>));
+ VERIFY((is_substitution_failure<vchar, xchar>));
+ VERIFY((is_substitution_failure<vchar, short>));
+ VERIFY((is_substitution_failure<vchar, ushort>));
+ COMPARE((is_substitution_failure<vchar, uint>), std::is_signed_v<char>);
+ VERIFY((is_substitution_failure<vchar, long>));
+ VERIFY((is_substitution_failure<vchar, ulong>));
+ VERIFY((is_substitution_failure<vchar, llong>));
+ VERIFY((is_substitution_failure<vchar, ullong>));
+ VERIFY((is_substitution_failure<vchar, float>));
+ VERIFY((is_substitution_failure<vchar, double>));
+ VERIFY((is_substitution_failure<vchar, vi8<char>>));
+ VERIFY((is_substitution_failure<vchar, vi8<uchar>>));
+ VERIFY((is_substitution_failure<vchar, vi8<schar>>));
+ VERIFY((is_substitution_failure<vchar, vi8<short>>));
+ VERIFY((is_substitution_failure<vchar, vi8<ushort>>));
+ VERIFY((is_substitution_failure<vchar, vi8<int>>));
+ VERIFY((is_substitution_failure<vchar, vi8<uint>>));
+ VERIFY((is_substitution_failure<vchar, vi8<long>>));
+ VERIFY((is_substitution_failure<vchar, vi8<ulong>>));
+ VERIFY((is_substitution_failure<vchar, vi8<llong>>));
+ VERIFY((is_substitution_failure<vchar, vi8<ullong>>));
+ VERIFY((is_substitution_failure<vchar, vi8<float>>));
+ VERIFY((is_substitution_failure<vchar, vi8<double>>));
+ VERIFY((is_substitution_failure<vi8<char>, vchar>));
+ VERIFY((is_substitution_failure<vi8<char>, vuchar>));
+ VERIFY((is_substitution_failure<vi8<char>, vschar>));
+ VERIFY((is_substitution_failure<vi8<char>, xchar>));
+ VERIFY((is_substitution_failure<vi8<char>, short>));
+ VERIFY((is_substitution_failure<vi8<char>, ushort>));
+ COMPARE((is_substitution_failure<vi8<char>, uint>),
+ std::is_signed_v<char>);
+ VERIFY((is_substitution_failure<vi8<char>, long>));
+ VERIFY((is_substitution_failure<vi8<char>, ulong>));
+ VERIFY((is_substitution_failure<vi8<char>, ullong>));
+ VERIFY((is_substitution_failure<vi8<char>, 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<char>, vi8<schar>>));
+ VERIFY((is_substitution_failure<vi8<char>, vi8<uchar>>));
+ }
+ else if constexpr (std::is_same_v<V, vschar>)
+ {
+ binary_op_return_type<vi8<schar>, schar, vi8<schar>>();
+ binary_op_return_type<vi8<schar>, int, vi8<schar>>();
+ binary_op_return_type<vi8<schar>, vi8<schar>, vi8<schar>>();
+
+ if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+ {
+ binary_op_return_type<vi8<short>, vi8<schar>>();
+ binary_op_return_type<vi8<int>, vi8<schar>>();
+ binary_op_return_type<vi8<long>, vi8<schar>>();
+ binary_op_return_type<vi8<llong>, vi8<schar>>();
+ binary_op_return_type<vi8<float>, vi8<schar>>();
+ binary_op_return_type<vi8<double>, vi8<schar>>();
+ }
+
+ VERIFY((is_substitution_failure<vi8<schar>, llong>));
+ VERIFY((is_substitution_failure<vi8<schar>, double>));
+ VERIFY((is_substitution_failure<vschar, vuchar>));
+ VERIFY((is_substitution_failure<vschar, uchar>));
+ VERIFY((is_substitution_failure<vschar, short>));
+ VERIFY((is_substitution_failure<vschar, ushort>));
+ VERIFY((is_substitution_failure<vschar, uint>));
+ VERIFY((is_substitution_failure<vschar, long>));
+ VERIFY((is_substitution_failure<vschar, ulong>));
+ VERIFY((is_substitution_failure<vschar, llong>));
+ VERIFY((is_substitution_failure<vschar, ullong>));
+ VERIFY((is_substitution_failure<vschar, float>));
+ VERIFY((is_substitution_failure<vschar, double>));
+ VERIFY((is_substitution_failure<vschar, vi8<schar>>));
+ VERIFY((is_substitution_failure<vschar, vi8<uchar>>));
+ VERIFY((is_substitution_failure<vschar, vi8<short>>));
+ VERIFY((is_substitution_failure<vschar, vi8<ushort>>));
+ VERIFY((is_substitution_failure<vschar, vi8<int>>));
+ VERIFY((is_substitution_failure<vschar, vi8<uint>>));
+ VERIFY((is_substitution_failure<vschar, vi8<long>>));
+ VERIFY((is_substitution_failure<vschar, vi8<ulong>>));
+ VERIFY((is_substitution_failure<vschar, vi8<llong>>));
+ VERIFY((is_substitution_failure<vschar, vi8<ullong>>));
+ VERIFY((is_substitution_failure<vschar, vi8<float>>));
+ VERIFY((is_substitution_failure<vschar, vi8<double>>));
+ VERIFY((is_substitution_failure<vi8<schar>, vschar>));
+ VERIFY((is_substitution_failure<vi8<schar>, vuchar>));
+ VERIFY((is_substitution_failure<vi8<schar>, uchar>));
+ VERIFY((is_substitution_failure<vi8<schar>, short>));
+ VERIFY((is_substitution_failure<vi8<schar>, ushort>));
+ VERIFY((is_substitution_failure<vi8<schar>, uint>));
+ VERIFY((is_substitution_failure<vi8<schar>, long>));
+ VERIFY((is_substitution_failure<vi8<schar>, ulong>));
+ VERIFY((is_substitution_failure<vi8<schar>, ullong>));
+ VERIFY((is_substitution_failure<vi8<schar>, float>));
+ VERIFY((is_substitution_failure<vi8<schar>, vi8<uchar>>));
+ VERIFY((is_substitution_failure<vi8<schar>, vi8<ushort>>));
+ VERIFY((is_substitution_failure<vi8<schar>, vi8<uint>>));
+ VERIFY((is_substitution_failure<vi8<schar>, vi8<ulong>>));
+ VERIFY((is_substitution_failure<vi8<schar>, vi8<ullong>>));
+ }
+ else if constexpr (std::is_same_v<V, vuchar>)
+ {
+ VERIFY((is_substitution_failure<vi8<uchar>, llong>));
+
+ binary_op_return_type<vuchar, uint, vuchar>();
+ binary_op_return_type<vi8<uchar>, uchar, vi8<uchar>>();
+ binary_op_return_type<vi8<uchar>, int, vi8<uchar>>();
+ binary_op_return_type<vi8<uchar>, uint, vi8<uchar>>();
+ binary_op_return_type<vi8<uchar>, vi8<uchar>, vi8<uchar>>();
+
+ if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+ {
+ binary_op_return_type<vi8<short>, vi8<uchar>>();
+ binary_op_return_type<vi8<ushort>, vi8<uchar>>();
+ binary_op_return_type<vi8<int>, vi8<uchar>>();
+ binary_op_return_type<vi8<uint>, vi8<uchar>>();
+ binary_op_return_type<vi8<long>, vi8<uchar>>();
+ binary_op_return_type<vi8<ulong>, vi8<uchar>>();
+ binary_op_return_type<vi8<llong>, vi8<uchar>>();
+ binary_op_return_type<vi8<ullong>, vi8<uchar>>();
+ binary_op_return_type<vi8<float>, vi8<uchar>>();
+ binary_op_return_type<vi8<double>, vi8<uchar>>();
+ }
+
+ VERIFY((is_substitution_failure<vi8<uchar>, ullong>));
+ VERIFY((is_substitution_failure<vi8<uchar>, double>));
+ VERIFY((is_substitution_failure<vuchar, schar>));
+ VERIFY((is_substitution_failure<vuchar, vschar>));
+ VERIFY((is_substitution_failure<vuchar, short>));
+ VERIFY((is_substitution_failure<vuchar, ushort>));
+ VERIFY((is_substitution_failure<vuchar, long>));
+ VERIFY((is_substitution_failure<vuchar, ulong>));
+ VERIFY((is_substitution_failure<vuchar, llong>));
+ VERIFY((is_substitution_failure<vuchar, ullong>));
+ VERIFY((is_substitution_failure<vuchar, float>));
+ VERIFY((is_substitution_failure<vuchar, double>));
+ VERIFY((is_substitution_failure<vuchar, vi8<schar>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<uchar>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<short>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<ushort>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<int>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<uint>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<long>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<ulong>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<llong>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<ullong>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<float>>));
+ VERIFY((is_substitution_failure<vuchar, vi8<double>>));
+ VERIFY((is_substitution_failure<vi8<uchar>, schar>));
+ VERIFY((is_substitution_failure<vi8<uchar>, vschar>));
+ VERIFY((is_substitution_failure<vi8<uchar>, vuchar>));
+ VERIFY((is_substitution_failure<vi8<uchar>, short>));
+ VERIFY((is_substitution_failure<vi8<uchar>, ushort>));
+ VERIFY((is_substitution_failure<vi8<uchar>, long>));
+ VERIFY((is_substitution_failure<vi8<uchar>, ulong>));
+ VERIFY((is_substitution_failure<vi8<uchar>, float>));
+ VERIFY((is_substitution_failure<vi8<uchar>, vi8<schar>>));
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/test_values.h"
+
+template <class T>
+ constexpr T
+ genHalfBits()
+ {
+ if constexpr (std::is_floating_point_v<T>)
+ return 0;
+ else
+ return std::__finite_max_v<T> >> (std::__digits_v<T> / 2);
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ using T = typename V::value_type;
+ constexpr auto min = std::__finite_min_v<T>;
+ constexpr auto norm_min = std::__norm_min_v<T>;
+ constexpr auto max = std::__finite_max_v<T>;
+ { // compares
+ COMPARE(V(0) == make_vec<V>({0, 1}, 0), make_mask<M>({1, 0}));
+ COMPARE(V(0) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({1, 0, 0}));
+ COMPARE(V(1) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 1, 0}));
+ COMPARE(V(2) == make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 0, 1}));
+ COMPARE(V(0) < make_vec<V>({0, 1, 2}, 0), make_mask<M>({0, 1, 1}));
+
+ constexpr T half = genHalfBits<T>();
+ 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<typename V::value_type,
+ std::experimental::simd_abi::scalar>
+ 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<V>({1, 2, 3, 4, 5, 6, 7});
+ COMPARE(x = x + y, make_vec<V>({2, 3, 4, 5, 6, 7, 8}));
+ COMPARE(x = x + -y, V(1));
+ COMPARE(x += y, make_vec<V>({2, 3, 4, 5, 6, 7, 8}));
+ COMPARE(x, make_vec<V>({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<V>({1, 2, 3, 4, 5, 6, 7});
+ COMPARE(x = y - x, make_vec<V>({0, 1, 2, 3, 4, 5, 6}));
+ COMPARE(x = y - x, V(1));
+ COMPARE(y -= x, make_vec<V>({0, 1, 2, 3, 4, 5, 6}));
+ COMPARE(y, make_vec<V>({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<V>({1, 2, 3, 4, 5, 6, 7});
+ COMPARE(x = x * y, make_vec<V>({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> ? T(norm_min * 3) : min})
+ {
+ x = n / 2;
+ COMPARE(x * y, V(n));
+ }
+ if (std::is_integral<T>::value && std::is_unsigned<T>::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<V>({1, 2, 3}), make_vec<V>({2, 4, 6}));
+ COMPARE(x, make_vec<V>({2, 4, 6}));
+ }
+
+ // divides
+ constexpr bool is_iec559 = __GCC_IEC_559 >= 2;
+ if constexpr (std::is_floating_point_v<T> && !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<V>({1, 2, 3, 4, 5, 6, 7});
+ ULP_COMPARE(y / x,
+ make_vec<V>(
+ {T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)}),
+ 1);
+
+ test_values<V>({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<V>({1, 2, 3, 4, 5, 6, 7});
+ COMPARE(y / x,
+ make_vec<V>({T(.5), T(1), T(1.5), T(2), T(2.5), T(3), T(3.5)}));
+
+ y = make_vec<V>({max, norm_min});
+ V ref = make_vec<V>({T(max / 2), T(norm_min / 2)});
+ COMPARE(y / x, ref);
+
+ y = make_vec<V>({norm_min, max});
+ ref = make_vec<V>({T(norm_min / 2), T(max / 2)});
+ COMPARE(y / x, ref);
+
+ y = make_vec<V>({max, T(norm_min + 1)});
+ COMPARE(y / y, V(1));
+
+ ref = make_vec<V>({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<V>({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);
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <random>
+
+template <typename V>
+ 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<T>)
+ {
+ 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<V>({}, {1000}, [](V x) {
+ // avoid over-/underflow on signed integers:
+ if constexpr (std::is_signed_v<T> && std::is_integral_v<T>)
+ 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<T>)
+ 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);
+ });
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(0);
+ vir::test::setFuzzyness<double>(0);
+
+ using T = typename V::value_type;
+ test_values_2arg<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>,
+ std::__denorm_min_v<T>, std::__norm_min_v<T> / 3, -0.,
+#endif
+ +0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+ {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<int, V::size()>;
+ IV quo = {};
+ const V totest = remquo(a, b, &quo);
+ auto&& expected
+ = [&](const auto& v, const auto& w) -> std::pair<const V, const IV> {
+ std::pair<V, IV> 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);
+ });
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+template <typename V>
+ 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<typename V::abi_type,
+ std::experimental::simd_abi::fixed_size<V::size()>>)
+ n *= 2;
+ VERIFY(sizeof(V) <= n) << "\nsizeof(V): " << sizeof(V) << "\nn: " << n;
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/simd_view.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ using std::cos;
+ using std::sin;
+ using T = typename V::value_type;
+
+ vir::test::setFuzzyness<float>(2);
+ vir::test::setFuzzyness<double>(1);
+
+ const auto& testdata = referenceData<function::sincos, T>();
+ std::experimental::experimental::simd_view<V>(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;
+ });
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+
+template <typename V, bool ConstProp, typename F>
+ auto
+ gen(const F& fun)
+ {
+ if constexpr (ConstProp)
+ return V(fun);
+ else
+ return make_value_unknown(V(fun));
+ }
+
+template <typename V, bool ConstProp>
+ void
+ split_concat()
+ {
+ using T = typename V::value_type;
+ if constexpr (V::size() * 3
+ <= std::experimental::simd_abi::max_fixed_size<T>)
+ {
+ 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<V, ConstProp>([](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<T, N0>>;
+ using V1 = std::experimental::simd<
+ T, std::experimental::simd_abi::deduce_t<T, N1>>;
+ {
+ auto x = std::experimental::split<N0, N0, N1>(a);
+ COMPARE(std::tuple_size<decltype(x)>::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<N> 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<N0, N1, N0>(a);
+ COMPARE(std::tuple_size<decltype(x)>::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<N> 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<N1, N0, N0>(a);
+ COMPARE(std::tuple_size<decltype(x)>::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<N> 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<V, ConstProp>([](auto i) -> T { return i; });
+ constexpr auto N0 = V::size() / 3;
+ using V0 = std::experimental::simd<
+ T, std::experimental::simd_abi::deduce_t<T, N0>>;
+ using V1 = std::experimental::simd<
+ T, std::experimental::simd_abi::deduce_t<T, 2 * N0>>;
+ {
+ auto [x, y, z] = std::experimental::split<N0, N0, N0>(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<decltype(b)>(a));
+ COMPARE(simd_cast<V>(b), a);
+ }
+ {
+ auto [x, y] = std::experimental::split<N0, 2 * N0>(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<decltype(b)>(a));
+ COMPARE(simd_cast<V>(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<decltype(b)>(a));
+ COMPARE(simd_cast<V>(b), a);
+ }
+ }
+
+ if constexpr ((V::size() & 1) == 0)
+ {
+ using std::experimental::simd;
+ using std::experimental::simd_abi::deduce_t;
+ using V0 = simd<T, deduce_t<T, V::size()>>;
+ using V2 = simd<T, deduce_t<T, 2>>;
+ using V3 = simd<T, deduce_t<T, V::size() / 2>>;
+
+ const V a = gen<V, ConstProp>([](auto i) -> T { return i; });
+
+ std::array<V2, V::size() / 2> v2s = std::experimental::split<V2>(a);
+ int offset = 0;
+ for (V2 test : v2s)
+ {
+ COMPARE(test, V2([&](auto i) -> T { return i + offset; }));
+ offset += 2;
+ }
+ COMPARE(concat(v2s), simd_cast<V0>(a));
+
+ std::array<V3, 2> v3s = std::experimental::split<V3>(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<V0>(a));
+ }
+ }
+
+template <typename V>
+ void
+ test()
+ {
+ split_concat<V, true>();
+ split_concat<V, false>();
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+template <typename V>
+ 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<T> * simd_size_v<T> == V::size())
+ {
+ M k(true);
+ VERIFY(all_of(k)) << k;
+ const auto parts = split<simd_mask<T>>(k);
+ for (auto k2 : parts)
+ {
+ VERIFY(all_of(k2)) << k2;
+ COMPARE(typeid(k2), typeid(simd_mask<T>));
+ }
+ }
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+ void
+ test()
+ {
+ vir::test::setFuzzyness<float>(1);
+ vir::test::setFuzzyness<double>(1);
+
+ using T = typename V::value_type;
+ test_values<V>(
+ {
+#ifdef __STDC_IEC_559__
+ std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+ std::__denorm_min_v<T>, std::__norm_min_v<T> / 3,
+#endif
+ +0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+ {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));
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/test_values.h"
+#include "bits/verify.h"
+
+template <typename V>
+ void
+ test()
+ {
+ using T = typename V::value_type;
+ constexpr T inf = std::__infinity_v<T>;
+ constexpr T denorm_min = std::__denorm_min_v<T>;
+ constexpr T norm_min = std::__norm_min_v<T>;
+ constexpr T max = std::__finite_max_v<T>;
+ constexpr T min = std::__finite_min_v<T>;
+ test_values<V>(
+ {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<V>(
+ {
+#ifdef __SUPPORT_SNAN__
+ std::__signaling_NaN_v<T>,
+#endif
+ std::__quiet_NaN_v<T>},
+ [](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
+ }
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/metahelpers.h"
+
+template <class V>
+ struct Convertible
+ {
+ operator V() const { return V(4); }
+ };
+
+template <class M, class T>
+ constexpr bool
+ where_is_ill_formed_impl(M, const T&, float)
+ {
+ return true;
+ }
+
+template <class M, class T>
+ constexpr auto
+ where_is_ill_formed_impl(M m, const T& v, int)
+ -> std::conditional_t<true, bool, decltype(std::experimental::where(m, v))>
+ {
+ return false;
+ }
+
+template <class M, class T>
+ constexpr bool
+ where_is_ill_formed(M m, const T& v)
+ {
+ return where_is_ill_formed_impl(m, v, int());
+ }
+
+template <typename T>
+ 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 <typename V>
+ void
+ test()
+ {
+ using M = typename V::mask_type;
+ using T = typename V::value_type;
+ where_fundamental<T>();
+ VERIFY(!(sfinae_is_callable<V>(
+ [](auto x) -> decltype(where(true, x))* { return nullptr; })));
+
+ const V indexes([](int i) { return i + 1; });
+ const M alternating_mask = make_mask<M>({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<V>();
+ 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<V>();
+ 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<T>)
+ 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);
+ }