public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: Matthias Kretz <m.kretz@gsi.de>
To: <gcc-patches@gcc.gnu.org>, <libstdc++@gcc.gnu.org>
Subject: [PATCH] Add simd testsuite
Date: Wed, 16 Dec 2020 12:58:32 +0100	[thread overview]
Message-ID: <8364569.lWL0Ik8vYZ@excalibur> (raw)

[-- Attachment #1: Type: text/plain, Size: 12786 bytes --]

This is the second patch for std::experimental::simd, adding the testsuite. As 
discussed with Jonathan, the simd testsuite comes via its own check-simd 
target. The testsuite is so large that even marking all tests as "expensive", 
it still increased make check -j8 (with 8 cores) by more than 4 minutes (only 
to determine to compile and run nothing).

From: Matthias Kretz <kretz@kde.org>

The new check-simd target creates a subdirectory, generates the
necessary Makefiles, and spawns submakes to build and run the tests.

libstdc++-v3/ChangeLog:
	* scripts/check_simd: New file. This script is called from the
	the check-simd target. It determines a set of compiler flags and
	simulator setups for calling generate_makefile.sh and passes the
	information back to the check-simd target, which recurses to the
	generated Makefiles.
	* scripts/create_testsuite_files: Remove files below simd/tests/
	from testsuite_files and place them in testsuite_files_simd.
	* testsuite/Makefile.am: Add testsuite_files_simd. Add
	check-simd target.
	* testsuite/experimental/simd/driver.sh: New file. This script
	compiles and runs a given simd test, logging its output and
	status. It uses the timeout command to implement compile and
	test timeouts.
	* testsuite/experimental/simd/generate_makefile.sh: New file.
	This script generates a Makefile which uses driver.sh to compile
	and run the tests and collect the logs into a single log file.
	* testsuite/experimental/simd/tests/abs.cc: New file. Tests
	abs(simd).
	* testsuite/experimental/simd/tests/algorithms.cc: New file.
	Tests min/max(simd, simd).
	* testsuite/experimental/simd/tests/bits/conversions.h: New
	file. Contains functions to support tests involving conversions.
	* testsuite/experimental/simd/tests/bits/make_vec.h: New file.
	Support functions make_mask and make_vec.
	* testsuite/experimental/simd/tests/bits/mathreference.h: New
	file. Support functions to supply precomputed math function
	reference data.
	* testsuite/experimental/simd/tests/bits/metahelpers.h: New
	file. Support code for SFINAE testing.
	* testsuite/experimental/simd/tests/bits/simd_view.h: New file.
	* testsuite/experimental/simd/tests/bits/test_values.h: New
	file. Test functions to easily drive a test with simd objects
	initialized from a given list of values and a range of random
	values.
	* testsuite/experimental/simd/tests/bits/ulp.h: New file.
	Support code to determine the ULP distance of simd objects.
	* testsuite/experimental/simd/tests/bits/verify.h: New file.
	Test framework for COMPARE'ing simd objects and instantiating
	the test templates with value_type and ABI tag.
	* testsuite/experimental/simd/tests/broadcast.cc: New file. Test
	simd broadcasts.
	* testsuite/experimental/simd/tests/casts.cc: New file. Test
	simd casts.
	* testsuite/experimental/simd/tests/fpclassify.cc: New file.
	Test floating-point classification functions.
	* testsuite/experimental/simd/tests/frexp.cc: New file. Test
	frexp(simd).
	* testsuite/experimental/simd/tests/generator.cc: New file. Test
	simd generator constructor.
	* testsuite/experimental/simd/tests/hypot3_fma.cc: New file.
	Test 3-arg hypot(simd,simd,simd) and fma(simd,simd,sim).
	* testsuite/experimental/simd/tests/integer_operators.cc: New
	file. Test integer operators.
	* testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc:
	New file. Test ldexp(simd), scalbn(simd), scalbln(simd), and
	modf(simd).
	* testsuite/experimental/simd/tests/loadstore.cc: New file. Test
	(converting) simd loads and stores.
	* testsuite/experimental/simd/tests/logarithm.cc: New file. Test
	log*(simd).
	* testsuite/experimental/simd/tests/mask_broadcast.cc: New file.
	Test simd_mask broadcasts.
	* testsuite/experimental/simd/tests/mask_conversions.cc: New
	file. Test simd_mask conversions.
	* testsuite/experimental/simd/tests/mask_implicit_cvt.cc: New
	file. Test simd_mask implicit conversions.
	* testsuite/experimental/simd/tests/mask_loadstore.cc: New file.
	Test simd_mask loads and stores.
	* testsuite/experimental/simd/tests/mask_operator_cvt.cc: New
	file. Test simd_mask operators convert as specified.
	* testsuite/experimental/simd/tests/mask_operators.cc: New file.
	Test simd_mask compares, subscripts, and negation.
	* testsuite/experimental/simd/tests/mask_reductions.cc: New
	file. Test simd_mask reductions.
	* testsuite/experimental/simd/tests/math_1arg.cc: New file. Test
	1-arg math functions on simd.
	* testsuite/experimental/simd/tests/math_2arg.cc: New file. Test
	2-arg math functions on simd.
	* testsuite/experimental/simd/tests/operator_cvt.cc: New file.
	Test implicit conversions on simd binary operators behave as
	specified.
	* testsuite/experimental/simd/tests/operators.cc: New file. Test
	simd compares, subscripts, not, unary minus, plus, minus,
	multiplies, divides, increment, and decrement.
	* testsuite/experimental/simd/tests/reductions.cc: New file.
	Test reduce(simd).
	* testsuite/experimental/simd/tests/remqo.cc: New file. Test
	remqo(simd).
	* testsuite/experimental/simd/tests/simd.cc: New file. Basic
	sanity checks of simd types.
	* testsuite/experimental/simd/tests/sincos.cc: New file. Test
	sin(simd) and cos(simd).
	* testsuite/experimental/simd/tests/split_concat.cc: New file.
	Test split(simd) and concat(simd, simd).
	* testsuite/experimental/simd/tests/splits.cc: New file. Test
	split(simd_mask).
	* testsuite/experimental/simd/tests/trigonometric.cc: New file.
	Test remaining trigonometric functions on simd.
	* testsuite/experimental/simd/tests/trunc_ceil_floor.cc: New
	file. Test trunc(simd), ceil(simd), and floor(simd).
	* testsuite/experimental/simd/tests/where.cc: New file. Test
	masked operations using where.
---
 libstdc++-v3/scripts/check_simd               |   76 ++
 libstdc++-v3/scripts/create_testsuite_files   |    6 +-
 libstdc++-v3/testsuite/Makefile.am            |   17 +-
 .../testsuite/experimental/simd/driver.sh     |  249 ++++
 .../experimental/simd/generate_makefile.sh    |  250 ++++
 .../testsuite/experimental/simd/tests/abs.cc  |   24 +
 .../experimental/simd/tests/algorithms.cc     |   13 +
 .../simd/tests/bits/conversions.h             |  167 +++
 .../experimental/simd/tests/bits/make_vec.h   |   69 ++
 .../simd/tests/bits/mathreference.h           |  143 +++
 .../simd/tests/bits/metahelpers.h             |  147 +++
 .../experimental/simd/tests/bits/simd_view.h  |  131 ++
 .../simd/tests/bits/test_values.h             |  366 ++++++
 .../experimental/simd/tests/bits/ulp.h        |  111 ++
 .../experimental/simd/tests/bits/verify.h     |  336 ++++++
 .../experimental/simd/tests/broadcast.cc      |   87 ++
 .../experimental/simd/tests/casts.cc          |  152 +++
 .../experimental/simd/tests/fpclassify.cc     |   89 ++
 .../experimental/simd/tests/frexp.cc          |   68 ++
 .../experimental/simd/tests/generator.cc      |   41 +
 .../experimental/simd/tests/hypot3_fma.cc     |  134 +++
 .../simd/tests/integer_operators.cc           |  218 ++++
 .../simd/tests/ldexp_scalbn_scalbln_modf.cc   |  152 +++
 .../experimental/simd/tests/loadstore.cc      |  212 ++++
 .../experimental/simd/tests/logarithm.cc      |   66 ++
 .../experimental/simd/tests/mask_broadcast.cc |   50 +
 .../simd/tests/mask_conversions.cc            |   96 ++
 .../simd/tests/mask_implicit_cvt.cc           |   85 ++
 .../experimental/simd/tests/mask_loadstore.cc |  144 +++
 .../simd/tests/mask_operator_cvt.cc           |   94 ++
 .../experimental/simd/tests/mask_operators.cc |   40 +
 .../simd/tests/mask_reductions.cc             |  209 ++++
 .../experimental/simd/tests/math_1arg.cc      |   90 ++
 .../experimental/simd/tests/math_2arg.cc      |   62 +
 .../experimental/simd/tests/operator_cvt.cc   | 1055 +++++++++++++++++
 .../experimental/simd/tests/operators.cc      |  297 +++++
 .../experimental/simd/tests/reductions.cc     |   80 ++
 .../experimental/simd/tests/remqo.cc          |   53 +
 .../testsuite/experimental/simd/tests/simd.cc |   29 +
 .../experimental/simd/tests/sincos.cc         |   29 +
 .../experimental/simd/tests/split_concat.cc   |  166 +++
 .../experimental/simd/tests/splits.cc         |   21 +
 .../experimental/simd/tests/trigonometric.cc  |   24 +
 .../simd/tests/trunc_ceil_floor.cc            |   92 ++
 .../experimental/simd/tests/where.cc          |  119 ++
 45 files changed, 6156 insertions(+), 3 deletions(-)
 create mode 100755 libstdc++-v3/scripts/check_simd
 create mode 100755 libstdc++-v3/testsuite/experimental/simd/driver.sh
 create mode 100755 libstdc++-v3/testsuite/experimental/simd/
generate_makefile.sh
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/abs.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
algorithms.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
conversions.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
make_vec.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
mathreference.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
metahelpers.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
simd_view.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
test_values.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/bits/
verify.h
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
broadcast.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/casts.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
fpclassify.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
generator.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
hypot3_fma.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
integer_operators.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
ldexp_scalbn_scalbln_modf.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
loadstore.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
logarithm.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_broadcast.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_conversions.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_implicit_cvt.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_loadstore.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_operator_cvt.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_operators.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
mask_reductions.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
math_1arg.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
math_2arg.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
operator_cvt.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
operators.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
reductions.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/simd.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
split_concat.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/splits.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
trigonometric.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/
trunc_ceil_floor.cc
 create mode 100644 libstdc++-v3/testsuite/experimental/simd/tests/where.cc


--
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 std::experimental::simd              https://github.com/VcDevel/std-simd
──────────────────────────────────────────────────────────────────────────

[-- Attachment #2: 0001-Add-simd-testsuite.patch --]
[-- Type: text/x-patch, Size: 232361 bytes --]

diff --git a/libstdc++-v3/scripts/check_simd b/libstdc++-v3/scripts/check_simd
new file mode 100755
index 00000000000..2b7a17a64c9
--- /dev/null
+++ b/libstdc++-v3/scripts/check_simd
@@ -0,0 +1,76 @@
+#!/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" $CXX $INCLUDES $CXXFLAGS -static
+  echo "$subdir
+$flags
+$sim"
+done
diff --git a/libstdc++-v3/scripts/create_testsuite_files b/libstdc++-v3/scripts/create_testsuite_files
index 52bbb5cda5a..174c24ec05a 100755
--- a/libstdc++-v3/scripts/create_testsuite_files
+++ b/libstdc++-v3/scripts/create_testsuite_files
@@ -27,6 +27,7 @@ tmp="${TMPDIR:-/tmp}/ctt$$"
 tests_file_normal="$outdir/testsuite_files"
 tests_file_inter="$outdir/testsuite_files_interactive"
 tests_file_perf="$outdir/testsuite_files_performance"
+tests_file_simd="$outdir/testsuite_files_simd"
 
 cd $srcdir
 # This is the ugly version of "everything but the current directory".  It's
@@ -49,8 +50,11 @@ grep -v _xin $tmp.1 > $tmp.4
 grep performance $tmp.4 > $tests_file_perf
 grep -v performance $tmp.4 > $tmp.5
 
+grep simd/tests/ $tmp.5 > $tests_file_simd
+grep -v simd/tests/ $tmp.5 > $tmp.6
+
 # ...more filters go here.
-cp $tmp.5 $tests_file_normal
+cp $tmp.6 $tests_file_normal
 
 rm $tmp*
 exit 0
diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am
index 7b412411bfe..d2e282b62b9 100644
--- a/libstdc++-v3/testsuite/Makefile.am
+++ b/libstdc++-v3/testsuite/Makefile.am
@@ -31,7 +31,8 @@ include $(top_srcdir)/fragment.am
 lists_of_files = \
    testsuite_files \
    testsuite_files_interactive \
-   testsuite_files_performance
+   testsuite_files_performance \
+   testsuite_files_simd
 
 # This rule generates all of the testsuite_files* lists at once.
 ${lists_of_files}:
@@ -185,6 +186,18 @@ check-performance: testsuite_files_performance ${performance_script}
 	  CXXFLAGS='$(CXXFLAGS)'; export CXXFLAGS; \
 	  ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir})
 
+# Runs the simd tests.
+check-simd: $(srcdir)/experimental/simd/generate_makefile.sh \
+	    ${glibcxx_srcdir}/scripts/check_simd \
+	    testsuite_files_simd \
+	    ${glibcxx_builddir}/scripts/testsuite_flags
+	${glibcxx_srcdir}/scripts/check_simd "${glibcxx_srcdir}" "${glibcxx_builddir}" "$(CXXFLAGS)" | \
+	  while read subdir && read flags && read sim; do \
+	    $(MAKE) -C "$${subdir}" TESTFLAGS="$${flags}" GCC_TEST_SIMULATOR="$${sim}"; \
+	    tail -n6 $${subdir}/simd_testsuite.sum >> .simd.summary; \
+	  done; \
+	  cat .simd.summary && rm .simd.summary
+
 # Runs the testsuite in debug mode.
 debug_flags = "unix/-D_GLIBCXX_DEBUG"
 
@@ -234,4 +247,4 @@ CLEANFILES = *.txt *.tst *.exe core* filebuf_* tmp* ostream_* *.log *.sum \
 
 # To remove directories.
 clean-local:
-	rm -rf de fr debug parallel binaries normal*
+	rm -rf de fr debug parallel binaries normal* simd
diff --git a/libstdc++-v3/testsuite/experimental/simd/driver.sh b/libstdc++-v3/testsuite/experimental/simd/driver.sh
new file mode 100755
index 00000000000..aabef316f47
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/driver.sh
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+type=float
+abi=0
+name=
+srcdir="$(cd "${0%/*}" && pwd)/tests"
+sim="$GCC_TEST_SIMULATOR"
+quiet=false
+verbose=false
+timeout=180
+run_expensive=false
+if [ -n "$GCC_TEST_RUN_EXPENSIVE" ]; then
+  run_expensive=true
+fi
+keep_failed=false
+only=
+
+usage() {
+  cat <<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
diff --git a/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh
new file mode 100755
index 00000000000..a8caa4bcd4e
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+
+srcdir="$(cd "${0%/*}" && pwd)"
+driver="$srcdir/driver.sh"
+srcdir="$srcdir/tests"
+sim=
+rm_logs=true
+dst=.
+
+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.
+  -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
+    ;;
+  -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"
+echo CXXFLAGS = "$@" "\$(TESTFLAGS)" >> "$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
+
+.PHONY: clean help
+
+.PRECIOUS: %.log %.sum
+EOF
+} >> "$dst"
+
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc
new file mode 100644
index 00000000000..3f81bf03a40
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc
@@ -0,0 +1,24 @@
+#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;
+		       });
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc
new file mode 100644
index 00000000000..f79bb6b63d2
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc
@@ -0,0 +1,13 @@
+#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});
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h
new file mode 100644
index 00000000000..601b783cec6
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h
@@ -0,0 +1,167 @@
+#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]; }
+  };
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h
new file mode 100644
index 00000000000..f81135900e8
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h
@@ -0,0 +1,69 @@
+/*  This file is part of the Vc library. {
+Copyright © 2017 Matthias Kretz <kretz@kde.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the names of contributing organizations nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+}*/
+
+#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;
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h
new file mode 100644
index 00000000000..3e5892c2624
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h
@@ -0,0 +1,143 @@
+#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;
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h
new file mode 100644
index 00000000000..16c6b287690
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h
@@ -0,0 +1,147 @@
+#ifndef VC_TESTS_METAHELPERS_H_
+#define VC_TESTS_METAHELPERS_H_
+
+#include <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_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h
new file mode 100644
index 00000000000..b7fbaf883bf
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h
@@ -0,0 +1,131 @@
+/*  This file is part of the Vc library. {
+Copyright © 2018 Matthias Kretz <kretz@kde.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the names of contributing organizations nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+}*/
+
+#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_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h
new file mode 100644
index 00000000000..7acbb832900
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h
@@ -0,0 +1,366 @@
+#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_)
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h
new file mode 100644
index 00000000000..c1b9e7adb07
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h
@@ -0,0 +1,111 @@
+/*{
+Copyright © 2011-2018 Matthias Kretz <kretz@kde.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the names of contributing organizations nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+}*/
+
+#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
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h
new file mode 100644
index 00000000000..7ec6de7f16b
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h
@@ -0,0 +1,336 @@
+#ifndef TESTS_BITS_VERIFY_H_
+#define TESTS_BITS_VERIFY_H_
+
+#include <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_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc
new file mode 100644
index 00000000000..529280d87d4
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc
@@ -0,0 +1,87 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+enum unscoped_enum
+{ foo };
+
+enum class scoped_enum
+{ bar };
+
+struct convertible
+{
+  operator int();
+  operator float();
+};
+
+template <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>()));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc
new file mode 100644
index 00000000000..e2c0b108879
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc
@@ -0,0 +1,152 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+using std::experimental::static_simd_cast;
+
+template <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>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc
new file mode 100644
index 00000000000..87a80308ae9
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc
@@ -0,0 +1,89 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <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
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc
new file mode 100644
index 00000000000..1f9b30162cb
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc
@@ -0,0 +1,68 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <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
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc
new file mode 100644
index 00000000000..62ec716c82d
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc
@@ -0,0 +1,41 @@
+#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>);
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc
new file mode 100644
index 00000000000..330a79400ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc
@@ -0,0 +1,134 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+// 3-arg std::hypot needs to be fixed, this is a better reference:
+template <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)));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc
new file mode 100644
index 00000000000..9205d865aed
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc
@@ -0,0 +1,218 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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>));
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc
new file mode 100644
index 00000000000..e8a519612e8
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc
@@ -0,0 +1,152 @@
+// test only floattypes
+#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);
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc
new file mode 100644
index 00000000000..329c89688ed
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc
@@ -0,0 +1,212 @@
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/conversions.h"
+
+template <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>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc
new file mode 100644
index 00000000000..7578f1a8561
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc
@@ -0,0 +1,66 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/test_values.h"
+
+template <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));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc
new file mode 100644
index 00000000000..6fbadc67af7
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc
@@ -0,0 +1,50 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <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);
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc
new file mode 100644
index 00000000000..0248cd4cb47
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc
@@ -0,0 +1,96 @@
+#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>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc
new file mode 100644
index 00000000000..3fa8dab5799
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc
@@ -0,0 +1,85 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <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()>>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc
new file mode 100644
index 00000000000..5e3fd6d867c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc
@@ -0,0 +1,144 @@
+#include "bits/verify.h"
+
+// simd_mask generator functions
+template <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);
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc
new file mode 100644
index 00000000000..cb968d02785
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc
@@ -0,0 +1,94 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+using schar = 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>>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc
new file mode 100644
index 00000000000..f729adc55bf
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc
@@ -0,0 +1,40 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <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);
+    }
+  }
+
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc
new file mode 100644
index 00000000000..99912aad9c0
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc
@@ -0,0 +1,209 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// simd_mask generator functions
+template <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 {};
+	}));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc
new file mode 100644
index 00000000000..748fd1d3866
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc
@@ -0,0 +1,90 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/test_values.h"
+
+template <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));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc
new file mode 100644
index 00000000000..ef425fa4221
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc
@@ -0,0 +1,62 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <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));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc
new file mode 100644
index 00000000000..1c73e299981
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc
@@ -0,0 +1,1055 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// type with sizeof(char) but different signedness
+using xchar = 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>>));
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc
new file mode 100644
index 00000000000..566c5c994e8
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc
@@ -0,0 +1,297 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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);
+    }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc
new file mode 100644
index 00000000000..a663db23a61
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc
@@ -0,0 +1,80 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <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);
+    });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc
new file mode 100644
index 00000000000..87eb21ef098
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc
@@ -0,0 +1,53 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <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);
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc
new file mode 100644
index 00000000000..0744be5e191
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc
@@ -0,0 +1,29 @@
+#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;
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc
new file mode 100644
index 00000000000..ced3be49136
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc
@@ -0,0 +1,29 @@
+// test only floattypes
+// { dg-additional-files "reference-sincos-sp.dat" }
+// { dg-additional-files "reference-sincos-ep.dat" }
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/simd_view.h"
+#include "bits/test_values.h"
+
+template <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;
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc
new file mode 100644
index 00000000000..2e7cf66b227
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc
@@ -0,0 +1,166 @@
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+
+template <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>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc
new file mode 100644
index 00000000000..31db384f798
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc
@@ -0,0 +1,21 @@
+#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>));
+	  }
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc
new file mode 100644
index 00000000000..51fef12a87f
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc
@@ -0,0 +1,24 @@
+// test only floattypes
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <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));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc
new file mode 100644
index 00000000000..df105530efe
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc
@@ -0,0 +1,92 @@
+// test only floattypes
+#include "bits/test_values.h"
+#include "bits/verify.h"
+
+template <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
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/where.cc b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc
new file mode 100644
index 00000000000..603e5a4b262
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc
@@ -0,0 +1,119 @@
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/metahelpers.h"
+
+template <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);
+  }

             reply	other threads:[~2020-12-16 11:58 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-16 11:58 Matthias Kretz [this message]
2020-12-17 13:10 ` Jonathan Wakely
2020-12-18 15:25   ` Matthias Kretz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8364569.lWL0Ik8vYZ@excalibur \
    --to=m.kretz@gsi.de \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).