diff mbox series

[2/2] Add simd testsuite

Message ID 6884904.fbmDiqPtmF@excalibur
State New
Headers show
Series [1/2] Add std::experimental::simd from the Parallelism TS 2 | expand

Commit Message

Matthias Kretz Dec. 18, 2020, 3:49 p.m. UTC
Resending squashed patch after addressing Jonathan's comments.

From: Matthias Kretz <kretz@kde.org>

Add a new check-simd target to the testsuite. The new target creates a
subdirectory, generates the necessary Makefiles, and spawns submakes to
build and run the tests. Running this testsuite with defaults on my
machine takes half of the time the dejagnu testsuite required to only
determine whether to run tests. Since the simd testsuite integrated in
dejagnu increased the time of the whole libstdc++ testsuite by ~100%
this approach is a compromise for speed while not sacrificing coverage
too much. Since the test driver is invoked individually per test
executable from a Makefile, make's jobserver (-j) trivially parallelizes
testing.

Testing different flags and with simulator (or remote execution) is
possible. E.g. `make check-simd DRIVEROPTS=-q
target_list="unix{-m64,-m32}{-march=sandybridge,-march=skylake-avx512}{,-
ffast-math}"`
runs the testsuite 8 times in different subdirectories, using 8
different combinations of compiler flags, only outputs failing tests
(-q), and prints all summaries at the end. It skips most ABI tags by
default unless --run-expensive is passed to DRIVEROPTS or
GCC_TEST_RUN_EXPENSIVE is not empty.

To use a simulator, the CHECK_SIMD_CONFIG variable needs to point to a
shell script which calls `define_target <name> <flags> <simulator>` and
set target_list as needed. E.g.:
case "$target_triplet" in
x86_64-*)
  target_list="unix{-march=sandybridge,-march=skylake-avx512}
  ;;
powerpc64le-*)
  define_target power8 "-static -mcpu=power8" "/usr/bin/qemu-ppc64le -cpu 
power8"
  define_target power9 -mcpu=power9 "$HOME/bin/run_on_gcc135"
  target_list="power8 power9{,-ffast-math}"
  ;;
esac

libstdc++-v3/ChangeLog:
	* scripts/check_simd: New file. This script is called from the
	the check-simd target. It determines a set of compiler flags and
	simulator setups for calling generate_makefile.sh and passes the
	information back to the check-simd target, which recurses to the
	generated Makefiles.
	* scripts/create_testsuite_files: Remove files below simd/tests/
	from testsuite_files and place them in testsuite_files_simd.
	* testsuite/Makefile.am: Add testsuite_files_simd. Add
	check-simd target.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/experimental/simd/driver.sh: New file. This script
	compiles and runs a given simd test, logging its output and
	status. It uses the timeout command to implement compile and
	test timeouts.
	* testsuite/experimental/simd/generate_makefile.sh: New file.
	This script generates a Makefile which uses driver.sh to compile
	and run the tests and collect the logs into a single log file.
	* testsuite/experimental/simd/tests/abs.cc: New file. Tests
	abs(simd).
	* testsuite/experimental/simd/tests/algorithms.cc: New file.
	Tests min/max(simd, simd).
	* testsuite/experimental/simd/tests/bits/conversions.h: New
	file. Contains functions to support tests involving conversions.
	* testsuite/experimental/simd/tests/bits/make_vec.h: New file.
	Support functions make_mask and make_vec.
	* testsuite/experimental/simd/tests/bits/mathreference.h: New
	file. Support functions to supply precomputed math function
	reference data.
	* testsuite/experimental/simd/tests/bits/metahelpers.h: New
	file. Support code for SFINAE testing.
	* testsuite/experimental/simd/tests/bits/simd_view.h: New file.
	* testsuite/experimental/simd/tests/bits/test_values.h: New
	file. Test functions to easily drive a test with simd objects
	initialized from a given list of values and a range of random
	values.
	* testsuite/experimental/simd/tests/bits/ulp.h: New file.
	Support code to determine the ULP distance of simd objects.
	* testsuite/experimental/simd/tests/bits/verify.h: New file.
	Test framework for COMPARE'ing simd objects and instantiating
	the test templates with value_type and ABI tag.
	* testsuite/experimental/simd/tests/broadcast.cc: New file. Test
	simd broadcasts.
	* testsuite/experimental/simd/tests/casts.cc: New file. Test
	simd casts.
	* testsuite/experimental/simd/tests/fpclassify.cc: New file.
	Test floating-point classification functions.
	* testsuite/experimental/simd/tests/frexp.cc: New file. Test
	frexp(simd).
	* testsuite/experimental/simd/tests/generator.cc: New file. Test
	simd generator constructor.
	* testsuite/experimental/simd/tests/hypot3_fma.cc: New file.
	Test 3-arg hypot(simd,simd,simd) and fma(simd,simd,sim).
	* testsuite/experimental/simd/tests/integer_operators.cc: New
	file. Test integer operators.
	* testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc:
	New file. Test ldexp(simd), scalbn(simd), scalbln(simd), and
	modf(simd).
	* testsuite/experimental/simd/tests/loadstore.cc: New file. Test
	(converting) simd loads and stores.
	* testsuite/experimental/simd/tests/logarithm.cc: New file. Test
	log*(simd).
	* testsuite/experimental/simd/tests/mask_broadcast.cc: New file.
	Test simd_mask broadcasts.
	* testsuite/experimental/simd/tests/mask_conversions.cc: New
	file. Test simd_mask conversions.
	* testsuite/experimental/simd/tests/mask_implicit_cvt.cc: New
	file. Test simd_mask implicit conversions.
	* testsuite/experimental/simd/tests/mask_loadstore.cc: New file.
	Test simd_mask loads and stores.
	* testsuite/experimental/simd/tests/mask_operator_cvt.cc: New
	file. Test simd_mask operators convert as specified.
	* testsuite/experimental/simd/tests/mask_operators.cc: New file.
	Test simd_mask compares, subscripts, and negation.
	* testsuite/experimental/simd/tests/mask_reductions.cc: New
	file. Test simd_mask reductions.
	* testsuite/experimental/simd/tests/math_1arg.cc: New file. Test
	1-arg math functions on simd.
	* testsuite/experimental/simd/tests/math_2arg.cc: New file. Test
	2-arg math functions on simd.
	* testsuite/experimental/simd/tests/operator_cvt.cc: New file.
	Test implicit conversions on simd binary operators behave as
	specified.
	* testsuite/experimental/simd/tests/operators.cc: New file. Test
	simd compares, subscripts, not, unary minus, plus, minus,
	multiplies, divides, increment, and decrement.
	* testsuite/experimental/simd/tests/reductions.cc: New file.
	Test reduce(simd).
	* testsuite/experimental/simd/tests/remqo.cc: New file. Test
	remqo(simd).
	* testsuite/experimental/simd/tests/simd.cc: New file. Basic
	sanity checks of simd types.
	* testsuite/experimental/simd/tests/sincos.cc: New file. Test
	sin(simd) and cos(simd).
	* testsuite/experimental/simd/tests/split_concat.cc: New file.
	Test split(simd) and concat(simd, simd).
	* testsuite/experimental/simd/tests/splits.cc: New file. Test
	split(simd_mask).
	* testsuite/experimental/simd/tests/trigonometric.cc: New file.
	Test remaining trigonometric functions on simd.
	* testsuite/experimental/simd/tests/trunc_ceil_floor.cc: New
	file. Test trunc(simd), ceil(simd), and floor(simd).
	* testsuite/experimental/simd/tests/where.cc: New file. Test
	masked operations using where.
---
 libstdc++-v3/scripts/check_simd               |   75 ++
 libstdc++-v3/scripts/create_testsuite_files   |    6 +-
 libstdc++-v3/testsuite/Makefile.am            |   18 +-
 libstdc++-v3/testsuite/Makefile.in            |   18 +-
 .../testsuite/experimental/simd/driver.sh     |  249 ++++
 .../experimental/simd/generate_makefile.sh    |  261 ++++
 .../testsuite/experimental/simd/tests/abs.cc  |   41 +
 .../experimental/simd/tests/algorithms.cc     |   30 +
 .../simd/tests/bits/conversions.h             |  184 +++
 .../experimental/simd/tests/bits/make_vec.h   |   59 +
 .../simd/tests/bits/mathreference.h           |  160 +++
 .../simd/tests/bits/metahelpers.h             |  164 +++
 .../experimental/simd/tests/bits/simd_view.h  |  121 ++
 .../simd/tests/bits/test_values.h             |  383 ++++++
 .../experimental/simd/tests/bits/ulp.h        |  101 ++
 .../experimental/simd/tests/bits/verify.h     |  353 ++++++
 .../experimental/simd/tests/broadcast.cc      |  104 ++
 .../experimental/simd/tests/casts.cc          |  169 +++
 .../experimental/simd/tests/fpclassify.cc     |  106 ++
 .../experimental/simd/tests/frexp.cc          |   85 ++
 .../experimental/simd/tests/generator.cc      |   58 +
 .../experimental/simd/tests/hypot3_fma.cc     |  151 +++
 .../simd/tests/integer_operators.cc           |  218 ++++
 .../simd/tests/ldexp_scalbn_scalbln_modf.cc   |  169 +++
 .../experimental/simd/tests/loadstore.cc      |  229 ++++
 .../experimental/simd/tests/logarithm.cc      |   83 ++
 .../experimental/simd/tests/mask_broadcast.cc |   67 ++
 .../simd/tests/mask_conversions.cc            |  113 ++
 .../simd/tests/mask_implicit_cvt.cc           |  102 ++
 .../experimental/simd/tests/mask_loadstore.cc |  161 +++
 .../simd/tests/mask_operator_cvt.cc           |  111 ++
 .../experimental/simd/tests/mask_operators.cc |   57 +
 .../simd/tests/mask_reductions.cc             |  226 ++++
 .../experimental/simd/tests/math_1arg.cc      |  107 ++
 .../experimental/simd/tests/math_2arg.cc      |   79 ++
 .../experimental/simd/tests/operator_cvt.cc   | 1072 +++++++++++++++++
 .../experimental/simd/tests/operators.cc      |  297 +++++
 .../experimental/simd/tests/reductions.cc     |   97 ++
 .../experimental/simd/tests/remqo.cc          |   70 ++
 .../testsuite/experimental/simd/tests/simd.cc |   46 +
 .../experimental/simd/tests/sincos.cc         |   44 +
 .../experimental/simd/tests/split_concat.cc   |  183 +++
 .../experimental/simd/tests/splits.cc         |   38 +
 .../experimental/simd/tests/trigonometric.cc  |   41 +
 .../simd/tests/trunc_ceil_floor.cc            |  109 ++
 .../experimental/simd/tests/where.cc          |  136 +++
 46 files changed, 6746 insertions(+), 5 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
──────────────────────────────────────────────────────────────────────────

Comments

Jonathan Wakely Jan. 27, 2021, 4:45 p.m. UTC | #1
On 18/12/20 16:49 +0100, Matthias Kretz wrote:
>Resending squashed patch after addressing Jonathan's comments.
>
>From: Matthias Kretz <kretz@kde.org>
>
>Add a new check-simd target to the testsuite. The new target creates a
>subdirectory, generates the necessary Makefiles, and spawns submakes to
>build and run the tests. Running this testsuite with defaults on my
>machine takes half of the time the dejagnu testsuite required to only
>determine whether to run tests. Since the simd testsuite integrated in
>dejagnu increased the time of the whole libstdc++ testsuite by ~100%
>this approach is a compromise for speed while not sacrificing coverage
>too much. Since the test driver is invoked individually per test
>executable from a Makefile, make's jobserver (-j) trivially parallelizes
>testing.
>
>Testing different flags and with simulator (or remote execution) is
>possible. E.g. `make check-simd DRIVEROPTS=-q
>target_list="unix{-m64,-m32}{-march=sandybridge,-march=skylake-avx512}{,-
>ffast-math}"`
>runs the testsuite 8 times in different subdirectories, using 8
>different combinations of compiler flags, only outputs failing tests
>(-q), and prints all summaries at the end. It skips most ABI tags by
>default unless --run-expensive is passed to DRIVEROPTS or
>GCC_TEST_RUN_EXPENSIVE is not empty.
>
>To use a simulator, the CHECK_SIMD_CONFIG variable needs to point to a
>shell script which calls `define_target <name> <flags> <simulator>` and
>set target_list as needed. E.g.:
>case "$target_triplet" in
>x86_64-*)
>  target_list="unix{-march=sandybridge,-march=skylake-avx512}
>  ;;
>powerpc64le-*)
>  define_target power8 "-static -mcpu=power8" "/usr/bin/qemu-ppc64le -cpu
>power8"
>  define_target power9 -mcpu=power9 "$HOME/bin/run_on_gcc135"
>  target_list="power8 power9{,-ffast-math}"
>  ;;
>esac
>
>libstdc++-v3/ChangeLog:
>	* scripts/check_simd: New file. This script is called from the
>	the check-simd target. It determines a set of compiler flags and
>	simulator setups for calling generate_makefile.sh and passes the
>	information back to the check-simd target, which recurses to the
>	generated Makefiles.
>	* scripts/create_testsuite_files: Remove files below simd/tests/
>	from testsuite_files and place them in testsuite_files_simd.
>	* testsuite/Makefile.am: Add testsuite_files_simd. Add
>	check-simd target.
>	* testsuite/Makefile.in: Regenerate.
>	* testsuite/experimental/simd/driver.sh: New file. This script
>	compiles and runs a given simd test, logging its output and
>	status. It uses the timeout command to implement compile and
>	test timeouts.
>	* testsuite/experimental/simd/generate_makefile.sh: New file.
>	This script generates a Makefile which uses driver.sh to compile
>	and run the tests and collect the logs into a single log file.
>	* testsuite/experimental/simd/tests/abs.cc: New file. Tests
>	abs(simd).
>	* testsuite/experimental/simd/tests/algorithms.cc: New file.
>	Tests min/max(simd, simd).
>	* testsuite/experimental/simd/tests/bits/conversions.h: New
>	file. Contains functions to support tests involving conversions.
>	* testsuite/experimental/simd/tests/bits/make_vec.h: New file.
>	Support functions make_mask and make_vec.
>	* testsuite/experimental/simd/tests/bits/mathreference.h: New
>	file. Support functions to supply precomputed math function
>	reference data.
>	* testsuite/experimental/simd/tests/bits/metahelpers.h: New
>	file. Support code for SFINAE testing.
>	* testsuite/experimental/simd/tests/bits/simd_view.h: New file.
>	* testsuite/experimental/simd/tests/bits/test_values.h: New
>	file. Test functions to easily drive a test with simd objects
>	initialized from a given list of values and a range of random
>	values.
>	* testsuite/experimental/simd/tests/bits/ulp.h: New file.
>	Support code to determine the ULP distance of simd objects.
>	* testsuite/experimental/simd/tests/bits/verify.h: New file.
>	Test framework for COMPARE'ing simd objects and instantiating
>	the test templates with value_type and ABI tag.
>	* testsuite/experimental/simd/tests/broadcast.cc: New file. Test
>	simd broadcasts.
>	* testsuite/experimental/simd/tests/casts.cc: New file. Test
>	simd casts.
>	* testsuite/experimental/simd/tests/fpclassify.cc: New file.
>	Test floating-point classification functions.
>	* testsuite/experimental/simd/tests/frexp.cc: New file. Test
>	frexp(simd).
>	* testsuite/experimental/simd/tests/generator.cc: New file. Test
>	simd generator constructor.
>	* testsuite/experimental/simd/tests/hypot3_fma.cc: New file.
>	Test 3-arg hypot(simd,simd,simd) and fma(simd,simd,sim).
>	* testsuite/experimental/simd/tests/integer_operators.cc: New
>	file. Test integer operators.
>	* testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc:
>	New file. Test ldexp(simd), scalbn(simd), scalbln(simd), and
>	modf(simd).
>	* testsuite/experimental/simd/tests/loadstore.cc: New file. Test
>	(converting) simd loads and stores.
>	* testsuite/experimental/simd/tests/logarithm.cc: New file. Test
>	log*(simd).
>	* testsuite/experimental/simd/tests/mask_broadcast.cc: New file.
>	Test simd_mask broadcasts.
>	* testsuite/experimental/simd/tests/mask_conversions.cc: New
>	file. Test simd_mask conversions.
>	* testsuite/experimental/simd/tests/mask_implicit_cvt.cc: New
>	file. Test simd_mask implicit conversions.
>	* testsuite/experimental/simd/tests/mask_loadstore.cc: New file.
>	Test simd_mask loads and stores.
>	* testsuite/experimental/simd/tests/mask_operator_cvt.cc: New
>	file. Test simd_mask operators convert as specified.
>	* testsuite/experimental/simd/tests/mask_operators.cc: New file.
>	Test simd_mask compares, subscripts, and negation.
>	* testsuite/experimental/simd/tests/mask_reductions.cc: New
>	file. Test simd_mask reductions.
>	* testsuite/experimental/simd/tests/math_1arg.cc: New file. Test
>	1-arg math functions on simd.
>	* testsuite/experimental/simd/tests/math_2arg.cc: New file. Test
>	2-arg math functions on simd.
>	* testsuite/experimental/simd/tests/operator_cvt.cc: New file.
>	Test implicit conversions on simd binary operators behave as
>	specified.
>	* testsuite/experimental/simd/tests/operators.cc: New file. Test
>	simd compares, subscripts, not, unary minus, plus, minus,
>	multiplies, divides, increment, and decrement.
>	* testsuite/experimental/simd/tests/reductions.cc: New file.
>	Test reduce(simd).
>	* testsuite/experimental/simd/tests/remqo.cc: New file. Test
>	remqo(simd).
>	* testsuite/experimental/simd/tests/simd.cc: New file. Basic
>	sanity checks of simd types.
>	* testsuite/experimental/simd/tests/sincos.cc: New file. Test
>	sin(simd) and cos(simd).
>	* testsuite/experimental/simd/tests/split_concat.cc: New file.
>	Test split(simd) and concat(simd, simd).
>	* testsuite/experimental/simd/tests/splits.cc: New file. Test
>	split(simd_mask).
>	* testsuite/experimental/simd/tests/trigonometric.cc: New file.
>	Test remaining trigonometric functions on simd.
>	* testsuite/experimental/simd/tests/trunc_ceil_floor.cc: New
>	file. Test trunc(simd), ceil(simd), and floor(simd).
>	* testsuite/experimental/simd/tests/where.cc: New file. Test
>	masked operations using where.
>---
> libstdc++-v3/scripts/check_simd               |   75 ++
> libstdc++-v3/scripts/create_testsuite_files   |    6 +-
> libstdc++-v3/testsuite/Makefile.am            |   18 +-
> libstdc++-v3/testsuite/Makefile.in            |   18 +-
> .../testsuite/experimental/simd/driver.sh     |  249 ++++
> .../experimental/simd/generate_makefile.sh    |  261 ++++
> .../testsuite/experimental/simd/tests/abs.cc  |   41 +
> .../experimental/simd/tests/algorithms.cc     |   30 +
> .../simd/tests/bits/conversions.h             |  184 +++
> .../experimental/simd/tests/bits/make_vec.h   |   59 +
> .../simd/tests/bits/mathreference.h           |  160 +++
> .../simd/tests/bits/metahelpers.h             |  164 +++
> .../experimental/simd/tests/bits/simd_view.h  |  121 ++
> .../simd/tests/bits/test_values.h             |  383 ++++++
> .../experimental/simd/tests/bits/ulp.h        |  101 ++
> .../experimental/simd/tests/bits/verify.h     |  353 ++++++
> .../experimental/simd/tests/broadcast.cc      |  104 ++
> .../experimental/simd/tests/casts.cc          |  169 +++
> .../experimental/simd/tests/fpclassify.cc     |  106 ++
> .../experimental/simd/tests/frexp.cc          |   85 ++
> .../experimental/simd/tests/generator.cc      |   58 +
> .../experimental/simd/tests/hypot3_fma.cc     |  151 +++
> .../simd/tests/integer_operators.cc           |  218 ++++
> .../simd/tests/ldexp_scalbn_scalbln_modf.cc   |  169 +++
> .../experimental/simd/tests/loadstore.cc      |  229 ++++
> .../experimental/simd/tests/logarithm.cc      |   83 ++
> .../experimental/simd/tests/mask_broadcast.cc |   67 ++
> .../simd/tests/mask_conversions.cc            |  113 ++
> .../simd/tests/mask_implicit_cvt.cc           |  102 ++
> .../experimental/simd/tests/mask_loadstore.cc |  161 +++
> .../simd/tests/mask_operator_cvt.cc           |  111 ++
> .../experimental/simd/tests/mask_operators.cc |   57 +
> .../simd/tests/mask_reductions.cc             |  226 ++++
> .../experimental/simd/tests/math_1arg.cc      |  107 ++
> .../experimental/simd/tests/math_2arg.cc      |   79 ++
> .../experimental/simd/tests/operator_cvt.cc   | 1072 +++++++++++++++++
> .../experimental/simd/tests/operators.cc      |  297 +++++
> .../experimental/simd/tests/reductions.cc     |   97 ++
> .../experimental/simd/tests/remqo.cc          |   70 ++
> .../testsuite/experimental/simd/tests/simd.cc |   46 +
> .../experimental/simd/tests/sincos.cc         |   44 +
> .../experimental/simd/tests/split_concat.cc   |  183 +++
> .../experimental/simd/tests/splits.cc         |   38 +
> .../experimental/simd/tests/trigonometric.cc  |   41 +
> .../simd/tests/trunc_ceil_floor.cc            |  109 ++
> .../experimental/simd/tests/where.cc          |  136 +++
> 46 files changed, 6746 insertions(+), 5 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

Also pushed to master, with the attached patch to fix some
non-portable shell commands (as discussed with Matthias on IRC).

Thanks for this very significant contribution, and for your patience
over the two years since your first patch (and three since we started
talking about copyright assignments).

I'll regen the docs and add something to the release notes too.
Jonathan Wakely Jan. 27, 2021, 5:54 p.m. UTC | #2
On 27/01/21 16:45 +0000, Jonathan Wakely wrote:
>I'll regen the docs [...]

Done. Regenerating the docs needed the attached fix.
Jonathan Wakely Jan. 27, 2021, 6:31 p.m. UTC | #3
On 27/01/21 17:54 +0000, Jonathan Wakely wrote:
>> and add something to the release notes too.

Also done. Pushed to wwwdocs.
diff mbox series

Patch

diff --git a/libstdc++-v3/scripts/check_simd b/libstdc++-v3/scripts/check_simd
new file mode 100755
index 00000000000..25acf64c841
--- /dev/null
+++ b/libstdc++-v3/scripts/check_simd
@@ -0,0 +1,75 @@ 
+#!/bin/sh
+
+# check_simd <srcdir> <builddir> <CXXFLAGS>
+# Read config from $CHECK_SIMD_CONFIG file or $target_list
+
+scriptdir="$(cd "${0%/*}" && pwd)"
+srcdir="$1"
+builddir="$2"
+shift 2
+testdir="$builddir/testsuite"
+
+CXX="$("$builddir/scripts/testsuite_flags" --build-cxx)"
+CXXFLAGS="$("$builddir/scripts/testsuite_flags" --cxxflags) $1 -Wno-psabi"
+shift
+INCLUDES="$("$builddir/scripts/testsuite_flags" --build-includes)"
+
+target_triplet=$($CXX -dumpmachine)
+
+define_target() {
+  name="$1"
+  flags="$2"
+  sim="$3"
+  eval "$name=\"flags=\\\"$flags\\\"
+sim=\\\"$sim\\\"\""
+}
+
+if [ -f "$CHECK_SIMD_CONFIG" ]; then
+  . "$CHECK_SIMD_CONFIG"
+elif [ -z "$CHECK_SIMD_CONFIG" ]; then
+  if [ -z "$target_list" ]; then
+    target_list="unix"
+    case "$target_triplet" in
+      x86_64-*)      target_list="unix/-march=native" ;;
+      i?86-*)        target_list="unix/-march=native" ;;
+      powerpc64le-*) target_list="unix/-mcpu=power8" ;;
+      aarch64-*)     target_list="unix/-mcpu=cortex-a53" ;;
+      arm-*)         target_list="unix/-mcpu=cortex-a7" ;;
+    esac
+  fi
+else
+  echo "Error: File not found: \$CHECK_SIMD_CONFIG='$CHECK_SIMD_CONFIG'" 1>&2
+  exit 1
+fi
+
+# define unix with no flags and no simulator:
+define_target unix
+
+list="$target_list"
+
+# expand a{b,c} to a/b a/c
+while [ "${list#*\{}" != "${list}" ]; do
+  list="$(echo "$list" | \
+    sed -e 's#\([^ ]\+\){\([^{},]*\),\([^{}]*\)}\(/[^ ]*\)\?#\1/\2\4 \1{\3}\4#g' \
+        -e 's#{\([^{},]*\)}#/\1#g' \
+        -e 's#/ # #g' -e 's#/$##')"
+done
+
+# per a/b/c block extract flags and simulator, then make check-simd
+while [ ${#list} -gt 0 ]; do
+  a="${list%% *}"
+  if [ "$a" = "$list" ]; then
+    list=""
+  else
+    list="${list#${a} }"
+  fi
+  b="${a%%/*}"
+  eval "eval \"\$$b\""
+  flags="${flags}$(echo "${a#${b}}"|sed 's#/# #g')"
+  subdir="simd/$(echo "$flags" | sed 's#[= /-]##g')"
+  rm -f "${subdir}/Makefile"
+  $srcdir/testsuite/experimental/simd/generate_makefile.sh \
+    --destination="$testdir/$subdir" --sim="$sim" --testflags="$flags" \
+    $CXX $INCLUDES $CXXFLAGS -static-libgcc -static-libstdc++
+  echo "$subdir"
+done
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..fa9cc4753f3 100644
--- a/libstdc++-v3/testsuite/Makefile.am
+++ b/libstdc++-v3/testsuite/Makefile.am
@@ -31,7 +31,8 @@  include $(top_srcdir)/fragment.am
 lists_of_files = \
    testsuite_files \
    testsuite_files_interactive \
-   testsuite_files_performance
+   testsuite_files_performance \
+   testsuite_files_simd
 
 # This rule generates all of the testsuite_files* lists at once.
 ${lists_of_files}:
@@ -185,6 +186,19 @@  check-performance: testsuite_files_performance ${performance_script}
 	  CXXFLAGS='$(CXXFLAGS)'; export CXXFLAGS; \
 	  ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir})
 
+# Runs the simd tests.
+check-simd: $(srcdir)/experimental/simd/generate_makefile.sh \
+	    ${glibcxx_srcdir}/scripts/check_simd \
+	    testsuite_files_simd \
+	    ${glibcxx_builddir}/scripts/testsuite_flags
+	${glibcxx_srcdir}/scripts/check_simd "${glibcxx_srcdir}" "${glibcxx_builddir}" "$(CXXFLAGS)" | \
+	  while read subdir; do \
+	    $(MAKE) -C "$${subdir}"; \
+	    tail -n20 $${subdir}/simd_testsuite.sum | \
+	      grep -A20 -B1 'Summary ===' >> .simd.summary; \
+	  done; \
+	  cat .simd.summary && rm .simd.summary
+
 # Runs the testsuite in debug mode.
 debug_flags = "unix/-D_GLIBCXX_DEBUG"
 
@@ -234,4 +248,4 @@  CLEANFILES = *.txt *.tst *.exe core* filebuf_* tmp* ostream_* *.log *.sum \
 
 # To remove directories.
 clean-local:
-	rm -rf de fr debug parallel binaries normal*
+	rm -rf de fr debug parallel binaries normal* simd
diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in
index 1aac7edff7f..3900d6d87b4 100644
--- a/libstdc++-v3/testsuite/Makefile.in
+++ b/libstdc++-v3/testsuite/Makefile.in
@@ -380,7 +380,8 @@  AM_CPPFLAGS = $(GLIBCXX_INCLUDES) $(CPPFLAGS)
 lists_of_files = \
    testsuite_files \
    testsuite_files_interactive \
-   testsuite_files_performance
+   testsuite_files_performance \
+   testsuite_files_simd
 
 extract_symvers = $(glibcxx_builddir)/scripts/extract_symvers
 baseline_subdir := $(shell $(CXX) $(baseline_subdir_switch))
@@ -710,6 +711,19 @@  check-performance: testsuite_files_performance ${performance_script}
 	  CXXFLAGS='$(CXXFLAGS)'; export CXXFLAGS; \
 	  ${check_performance_script} ${glibcxx_srcdir} ${glibcxx_builddir})
 
+# Runs the simd tests.
+check-simd: $(srcdir)/experimental/simd/generate_makefile.sh \
+	    ${glibcxx_srcdir}/scripts/check_simd \
+	    testsuite_files_simd \
+	    ${glibcxx_builddir}/scripts/testsuite_flags
+	${glibcxx_srcdir}/scripts/check_simd "${glibcxx_srcdir}" "${glibcxx_builddir}" "$(CXXFLAGS)" | \
+	  while read subdir; do \
+	    $(MAKE) -C "$${subdir}"; \
+	    tail -n20 $${subdir}/simd_testsuite.sum | \
+	      grep -A20 -B1 'Summary ===' >> .simd.summary; \
+	  done; \
+	  cat .simd.summary && rm .simd.summary
+
 check-debug: site.exp
 	outputdir=debug; export outputdir; \
 	if test ! -d $${outputdir}; then \
@@ -742,7 +756,7 @@  check-performance-parallel: testsuite_files_performance ${performance_script}
 
 # To remove directories.
 clean-local:
-	rm -rf de fr debug parallel binaries normal*
+	rm -rf de fr debug parallel binaries normal* simd
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/libstdc++-v3/testsuite/experimental/simd/driver.sh b/libstdc++-v3/testsuite/experimental/simd/driver.sh
new file mode 100755
index 00000000000..aabef316f47
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/driver.sh
@@ -0,0 +1,249 @@ 
+#!/bin/sh
+
+type=float
+abi=0
+name=
+srcdir="$(cd "${0%/*}" && pwd)/tests"
+sim="$GCC_TEST_SIMULATOR"
+quiet=false
+verbose=false
+timeout=180
+run_expensive=false
+if [ -n "$GCC_TEST_RUN_EXPENSIVE" ]; then
+  run_expensive=true
+fi
+keep_failed=false
+only=
+
+usage() {
+  cat <<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..85a7f87271e
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/generate_makefile.sh
@@ -0,0 +1,261 @@ 
+#!/bin/sh
+
+srcdir="$(cd "${0%/*}" && pwd)"
+driver="$srcdir/driver.sh"
+srcdir="$srcdir/tests"
+sim=
+rm_logs=true
+dst=.
+testflags=
+
+usage() {
+  cat <<EOF
+Usage: $0 [Options] <g++ invocation>
+
+Options:
+  -h, --help          Print this message and exit.
+  --srcdir <path>     The source directory of the tests (default: $srcdir).
+  --sim <executable>  Path to an executable that is prepended to the test
+                      execution binary (default: none).
+  --keep-intermediate-logs
+                      Keep intermediate logs.
+  --testflags <flags> Force initial TESTFLAGS contents.
+  -d <path>, --destination <path>
+                      Destination for the generated Makefile. If the directory
+                      does not exist it is created (default: $dst).
+EOF
+}
+
+while [ $# -gt 0 ]; do
+  case "$1" in
+  -h|--help)
+    usage
+    exit
+    ;;
+  --testflags)
+    testflags="$2"
+    shift
+    ;;
+  --testflags=*)
+    testflags="${1#--testflags=}"
+    ;;
+  -d|--destination)
+    dst="$2"
+    shift
+    ;;
+  --destination=*)
+    dst="${1#--destination=}"
+    ;;
+  --keep-intermediate-logs)
+    rm_logs=false
+    ;;
+  --srcdir)
+    srcdir="$2"
+    shift
+    ;;
+  --srcdir=*)
+    srcdir="${1#--srcdir=}"
+    ;;
+  --sim)
+    sim="$2"
+    shift
+    ;;
+  --sim=*)
+    sim="${1#--sim=}"
+    ;;
+  --)
+    shift
+    break
+    ;;
+  *)
+    break
+    ;;
+  esac
+  shift
+done
+
+mkdir -p "$dst"
+dst="$dst/Makefile"
+if [ -f "$dst" ]; then
+  echo "Error: $dst already exists. Aborting." 1>&2
+  exit 1
+fi
+
+CXX="$1"
+shift
+
+echo "TESTFLAGS ?=" > "$dst"
+[ -n "$testflags" ] && echo "TESTFLAGS := $testflags \$(TESTFLAGS)" >> "$dst"
+echo CXXFLAGS = "$@" "\$(TESTFLAGS)" >> "$dst"
+[ -n "$sim" ] && echo "export GCC_TEST_SIMULATOR = $sim" >> "$dst"
+cat >> "$dst" <<EOF
+srcdir = ${srcdir}
+CXX = ${CXX}
+DRIVER = ${driver}
+DRIVEROPTS ?=
+
+all: simd_testsuite.sum
+
+simd_testsuite.sum: simd_testsuite.log
+	@echo "\n\t\t=== simd_testsuite \$(TESTFLAGS) Summary ===\n\n"\\
+	"# of expected passes:\t\t\$(shell grep -c '^PASS:' \$@)\n"\\
+	"# of unexpected failures:\t\$(shell grep -c '^FAIL:' \$@)\n"\\
+	"# of unsupported tests:\t\t\$(shell grep -c '^UNSUPPORTED:' \$@)"\\
+	  | tee -a \$@
+
+EOF
+
+all_types() {
+  src="$1"
+  cat <<EOF
+long double
+ldouble
+double
+double
+float
+float
+EOF
+  ([ -n "$src" ] && grep -q "test only floattypes" "$src") || \
+  cat <<EOF
+long long
+llong
+unsigned long long
+ullong
+unsigned long
+ulong
+long
+long
+int
+int
+unsigned int
+uint
+short
+short
+unsigned short
+ushort
+char
+char
+signed char
+schar
+unsigned char
+uchar
+char32_t
+char32_t
+char16_t
+char16_t
+wchar_t
+wchar_t
+EOF
+}
+
+all_tests() {
+  if [ -f testsuite_files_simd ]; then
+    sed 's,^experimental/simd/tests/,,' testsuite_files_simd | while read file; do
+      echo "$srcdir/$file"
+      echo "${file%.cc}"
+    done
+  else
+    for file in ${srcdir}/*.cc; do
+      echo "$file"
+      name="${file%.cc}"
+      echo "${name##*/}"
+    done
+  fi
+}
+
+{
+  rmline=""
+  if $rm_logs; then
+    rmline="
+	@rm \$^ \$(^:log=sum)"
+  fi
+  echo -n "simd_testsuite.log:"
+  all_tests | while read file && read name; do
+    echo -n " $name.log"
+  done
+  cat <<EOF
+
+	@cat $^ > \$@
+	@cat \$(^:log=sum) > \$(@:log=sum)${rmline}
+
+EOF
+  all_tests | while read file && read name; do
+    echo -n "$name.log:"
+    all_types "$file" | while read t && read type; do
+      echo -n " $name-$type.log"
+    done
+    cat <<EOF
+
+	@cat $^ > \$@
+	@cat \$(^:log=sum) > \$(@:log=sum)${rmline}
+
+EOF
+  done
+  all_types | while read t && read type; do
+    cat <<EOF
+%-$type.log: %-$type-0.log %-$type-1.log %-$type-2.log %-$type-3.log \
+%-$type-4.log %-$type-5.log %-$type-6.log %-$type-7.log \
+%-$type-8.log %-$type-9.log
+	@cat $^ > \$@
+	@cat \$(^:log=sum) > \$(@:log=sum)${rmline}
+
+EOF
+    for i in $(seq 0 9); do
+      cat <<EOF
+%-$type-$i.log: \$(srcdir)/%.cc
+	@\$(DRIVER) \$(DRIVEROPTS) -t "$t" -a $i -n \$* \$(CXX) \$(CXXFLAGS)
+
+EOF
+    done
+  done
+  echo 'run-%: export GCC_TEST_RUN_EXPENSIVE=yes\n'
+  all_tests | while read file && read name; do
+    echo "run-$name: $name.log"
+    all_types "$file" | while read t && read type; do
+      echo "run-$name-$type: $name-$type.log"
+      for i in $(seq 0 9); do
+        echo "run-$name-$type-$i: $name-$type-$i.log"
+      done
+    done
+    echo
+  done
+  cat <<EOF
+help:
+	@echo "use DRIVEROPTS=<options> to pass the following options:\n"\\
+	"-q, --quiet         Only print failures.\n"\\
+	"-v, --verbose       Print compiler and test output on failure.\n"\\
+	"-k, --keep-failed   Keep executables of failed tests.\n"\\
+	"--sim <executable>  Path to an executable that is prepended to the test\n"\\
+	"                    execution binary (default: the value of\n"\\
+	"                    GCC_TEST_SIMULATOR).\n"\\
+	"--timeout-factor <x>\n"\\
+	"                    Multiply the default timeout with x.\n"\\
+	"--run-expensive     Compile and run tests marked as expensive (default:\n"\\
+	"                    true if GCC_TEST_RUN_EXPENSIVE is set, false otherwise).\n"\\
+	"--only <pattern>    Compile and run only tests matching the given pattern.\n"
+	@echo "use TESTFLAGS=<flags> to pass additional compiler flags\n"
+	@echo "The following are some of the valid targets for this Makefile:"
+	@echo "... all"
+	@echo "... clean"
+	@echo "... help"
+EOF
+  all_tests | while read file && read name; do
+    echo "\t@echo '... run-${name}'"
+    all_types | while read t && read type; do
+      echo "\t@echo '... run-${name}-${type}'"
+      for i in $(seq 0 9); do
+        echo "\t@echo '... run-${name}-${type}-$i'"
+      done
+    done
+  done
+  cat <<EOF
+
+clean:
+	rm -f -- *.sum *.log *.exe
+
+.PHONY: clean help
+
+.PRECIOUS: %.log %.sum
+EOF
+} >> "$dst"
+
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc
new file mode 100644
index 00000000000..7d94cf47e1c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/abs.cc
@@ -0,0 +1,41 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include <cmath>    // abs & sqrt
+#include <cstdlib>  // integer abs
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    if constexpr (std::is_signed_v<typename V::value_type>)
+      {
+	using std::abs;
+	using T = typename V::value_type;
+	test_values<V>({std::__finite_max_v<T>, std::__norm_min_v<T>,
+			-std::__norm_min_v<T>, std::__finite_min_v<T>,
+			std::__finite_min_v<T> / 2, T(), -T(), T(-1), T(-2)},
+		       {1000}, [](V input) {
+			 const V expected(
+			   [&](auto i) { return T(std::abs(T(input[i]))); });
+			 COMPARE(abs(input), expected) << "input: " << input;
+		       });
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc
new file mode 100644
index 00000000000..78bce35f59c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/algorithms.cc
@@ -0,0 +1,30 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    V a{[](auto i) -> T { return i & 1u; }};
+    V b{[](auto i) -> T { return (i + 1u) & 1u; }};
+    COMPARE(min(a, b), V{0});
+    COMPARE(max(a, b), V{1});
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h
new file mode 100644
index 00000000000..e89221e1ede
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/conversions.h
@@ -0,0 +1,184 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <array>
+
+// is_conversion_undefined
+/* implementation-defined
+ * ======================
+ * §4.7 p3 (integral conversions)
+ *  If the destination type is signed, the value is unchanged if it can be
+ *  represented in the destination type (and bit-field width); otherwise, the
+ *  value is implementation-defined.
+ *
+ * undefined
+ * =========
+ * §4.9/1  (floating-point conversions)
+ *  If the source value is neither exactly represented in the destination type
+ *  nor between two adjacent destination values the result is undefined.
+ *
+ * §4.10/1 (floating-integral conversions)
+ *  floating point type can be converted to integer type.
+ *  The behavior is undefined if the truncated value cannot be
+ *  represented in the destination type.
+ *
+ * §4.10/2
+ *  integer can be converted to floating point type.
+ *  If the value being converted is outside the range of values that can be
+ *  represented, the behavior is undefined.
+ */
+template <typename To, typename From>
+  constexpr bool
+  is_conversion_undefined_impl(From x, std::true_type)
+  {
+    return x > static_cast<long double>(std::__finite_max_v<To>)
+	     || x < static_cast<long double>(std::__finite_min_v<To>);
+  }
+
+template <typename To, typename From>
+  constexpr bool
+  is_conversion_undefined_impl(From, std::false_type)
+  { return false; }
+
+template <typename To, typename From>
+  constexpr bool
+  is_conversion_undefined(From x)
+  {
+    static_assert(std::is_arithmetic<From>::value,
+		  "this overload is only meant for builtin arithmetic types");
+    return is_conversion_undefined_impl<To, From>(
+	     x, std::integral_constant<
+		  bool, std::is_floating_point<From>::value
+			  && (std::is_integral<To>::value
+				|| (std::is_floating_point<To>::value
+				      && sizeof(From) > sizeof(To)))>());
+  }
+
+static_assert(is_conversion_undefined<uint>(float(0x100000000LL)),
+	      "testing my expectations of is_conversion_undefined");
+static_assert(!is_conversion_undefined<float>(0x100000000LL),
+	      "testing my expectations of is_conversion_undefined");
+
+template <typename To, typename T, typename A>
+  inline std::experimental::simd_mask<T, A>
+  is_conversion_undefined(const std::experimental::simd<T, A>& x)
+  {
+    std::experimental::simd_mask<T, A> k = false;
+    for (std::size_t i = 0; i < x.size(); ++i)
+      k[i] = is_conversion_undefined(x[i]);
+    return k;
+  }
+
+template <class T>
+  constexpr T
+  genHalfBits()
+  { return std::__finite_max_v<T> >> (std::__digits_v<T> / 2); }
+
+template <>
+  constexpr long double
+  genHalfBits<long double>()
+  { return 0; }
+
+template <>
+  constexpr double
+  genHalfBits<double>()
+  { return 0; }
+
+template <>
+  constexpr float
+  genHalfBits<float>()
+  { return 0; }
+
+template <class U, class T, class UU>
+  constexpr U
+  avoid_ub(UU x)
+  { return is_conversion_undefined<T>(U(x)) ? U(0) : U(x); }
+
+template <class U, class T, class UU>
+  constexpr U
+  avoid_ub2(UU x)
+  { return is_conversion_undefined<U>(x) ? U(0) : avoid_ub<U, T>(x); }
+
+// conversion test input data
+template <class U, class T>
+  static const std::array<U, 53> cvt_input_data = {{
+    avoid_ub<U, T>(0xc0000080U),
+    avoid_ub<U, T>(0xc0000081U),
+    avoid_ub<U, T>(0xc0000082U),
+    avoid_ub<U, T>(0xc0000084U),
+    avoid_ub<U, T>(0xc0000088U),
+    avoid_ub<U, T>(0xc0000090U),
+    avoid_ub<U, T>(0xc00000A0U),
+    avoid_ub<U, T>(0xc00000C0U),
+    avoid_ub<U, T>(0xc000017fU),
+    avoid_ub<U, T>(0xc0000180U),
+    avoid_ub<U, T>(0x100000001LL),
+    avoid_ub<U, T>(0x100000011LL),
+    avoid_ub<U, T>(0x100000111LL),
+    avoid_ub<U, T>(0x100001111LL),
+    avoid_ub<U, T>(0x100011111LL),
+    avoid_ub<U, T>(0x100111111LL),
+    avoid_ub<U, T>(0x101111111LL),
+    avoid_ub<U, T>(-0x100000001LL),
+    avoid_ub<U, T>(-0x100000011LL),
+    avoid_ub<U, T>(-0x100000111LL),
+    avoid_ub<U, T>(-0x100001111LL),
+    avoid_ub<U, T>(-0x100011111LL),
+    avoid_ub<U, T>(-0x100111111LL),
+    avoid_ub<U, T>(-0x101111111LL),
+    avoid_ub<U, T>(std::__norm_min_v<U>),
+    avoid_ub<U, T>(std::__norm_min_v<U> + 1),
+    avoid_ub<U, T>(std::__finite_min_v<U>),
+    avoid_ub<U, T>(std::__finite_min_v<U> + 1),
+    avoid_ub<U, T>(-1),
+    avoid_ub<U, T>(-10),
+    avoid_ub<U, T>(-100),
+    avoid_ub<U, T>(-1000),
+    avoid_ub<U, T>(-10000),
+    avoid_ub<U, T>(0),
+    avoid_ub<U, T>(1),
+    avoid_ub<U, T>(genHalfBits<U>() - 1),
+    avoid_ub<U, T>(genHalfBits<U>()),
+    avoid_ub<U, T>(genHalfBits<U>() + 1),
+    avoid_ub<U, T>(std::__finite_max_v<U> - 1),
+    avoid_ub<U, T>(std::__finite_max_v<U>),
+    avoid_ub<U, T>(std::__finite_max_v<U> - 0xff),
+    avoid_ub<U, T>(std::__finite_max_v<U> - 0xff),
+    avoid_ub<U, T>(std::__finite_max_v<U> - 0x55),
+    avoid_ub<U, T>(-(std::__finite_min_v<U> + 1)),
+    avoid_ub<U, T>(-std::__finite_max_v<U>),
+    avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 6 - 1)),
+    avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 6 - 1)),
+    avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 4 - 1)),
+    avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 4 - 1)),
+    avoid_ub<U, T>(std::__finite_max_v<U> / std::pow(2., sizeof(T) * 2 - 1)),
+    avoid_ub2<U, T>(-std::__finite_max_v<U> / std::pow(2., sizeof(T) * 2 - 1)),
+    avoid_ub<U, T>(std::__finite_max_v<T> - 1),
+    avoid_ub<U, T>(std::__finite_max_v<T> * 0.75),
+  }};
+
+template <class T, class U>
+  struct cvt_inputs
+  {
+    static constexpr size_t
+    size()
+    { return cvt_input_data<U, T>.size(); }
+
+    U
+    operator[](size_t i) const
+    { return cvt_input_data<U, T>[i]; }
+  };
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h
new file mode 100644
index 00000000000..ee0d436f9ae
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/make_vec.h
@@ -0,0 +1,59 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/simd>
+
+template <class M>
+  inline M
+  make_mask(const std::initializer_list<bool> &init)
+  {
+    std::size_t i = 0;
+    M r = {};
+    for (;;)
+      {
+	for (bool x : init)
+	  {
+	    r[i] = x;
+	    if (++i == M::size())
+	      {
+		return r;
+	      }
+	  }
+      }
+  }
+
+template <class V>
+  inline V
+  make_vec(const std::initializer_list<typename V::value_type> &init,
+	   typename V::value_type inc = 0)
+  {
+    std::size_t i = 0;
+    V r = {};
+    typename V::value_type base = 0;
+    for (;;)
+      {
+	for (auto x : init)
+	  {
+	    r[i] = base + x;
+	    if (++i == V::size())
+	      {
+		return r;
+	      }
+	  }
+	base += inc;
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h
new file mode 100644
index 00000000000..2ed2bb35e3c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/mathreference.h
@@ -0,0 +1,160 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <tuple>
+#include <utility>
+#include <cstdio>
+
+template <typename T>
+  struct SincosReference
+  {
+    T x, s, c;
+
+    std::tuple<const T &, const T &, const T &>
+    as_tuple() const
+    { return std::tie(x, s, c); }
+  };
+
+template <typename T>
+  struct Reference {
+    T x, ref;
+
+    std::tuple<const T &, const T &>
+    as_tuple() const
+    { return std::tie(x, ref); }
+  };
+
+template <typename T>
+  struct Array
+  {
+    std::size_t size_;
+    const T *data_;
+
+    Array()
+    : size_(0), data_(nullptr) {}
+
+    Array(size_t s, const T *p)
+    : size_(s), data_(p) {}
+
+    const T*
+    begin() const
+    { return data_; }
+
+    const T*
+    end() const
+    { return data_ + size_; }
+
+    std::size_t
+    size() const
+    { return size_; }
+  };
+
+namespace function {
+  struct sincos{ static constexpr const char *const str = "sincos"; };
+  struct atan  { static constexpr const char *const str = "atan"; };
+  struct asin  { static constexpr const char *const str = "asin"; };
+  struct acos  { static constexpr const char *const str = "acos"; };
+  struct log   { static constexpr const char *const str = "ln"; };
+  struct log2  { static constexpr const char *const str = "log2"; };
+  struct log10 { static constexpr const char *const str = "log10"; };
+}
+
+template <class F>
+  struct testdatatype_for_function
+  {
+    template <class T>
+      using type = Reference<T>;
+  };
+
+template <>
+  struct testdatatype_for_function<function::sincos>
+  {
+    template <class T>
+      using type = SincosReference<T>;
+  };
+
+template <class F, class T>
+  using testdatatype_for_function_t
+    = typename testdatatype_for_function<F>::template type<T>;
+
+template<typename T>
+  struct StaticDeleter
+  {
+    const T *ptr;
+
+    StaticDeleter(const T *p)
+    : ptr(p) {}
+
+    ~StaticDeleter()
+    { delete[] ptr; }
+  };
+
+template <class F, class T>
+  inline std::string filename()
+  {
+    static_assert(std::is_floating_point<T>::value, "");
+    static const auto cache
+      = std::string("reference-") + F::str
+      + (sizeof(T) == 4 && std::__digits_v<T> == 24
+	 && std::__max_exponent_v<T> == 128
+	 ? "-sp"
+	 : (sizeof(T) == 8
+	    && std::__digits_v<T> == 53
+	    && std::__max_exponent_v<T> == 1024
+	    ? "-dp"
+	    : (sizeof(T) == 16 && std::__digits_v<T> == 64
+	       && std::__max_exponent_v<T> == 16384
+	       ? "-ep"
+	       : (sizeof(T) == 16 && std::__digits_v<T> == 113
+		  && std::__max_exponent_v<T> == 16384
+		  ? "-qp"
+		  : "-unknown"))))
+      + ".dat";
+    return cache;
+  }
+
+template <class Fun, class T, class Ref = testdatatype_for_function_t<Fun, T>>
+  Array<Ref>
+  referenceData()
+  {
+    static Array<Ref> data;
+    if (data.data_ == nullptr)
+      {
+	FILE* file = std::fopen(filename<Fun, T>().c_str(), "rb");
+	if (file)
+	  {
+	    std::fseek(file, 0, SEEK_END);
+	    const size_t size = std::ftell(file) / sizeof(Ref);
+	    std::rewind(file);
+	    auto                      mem = new Ref[size];
+	    static StaticDeleter<Ref> _cleanup(data.data_);
+	    data.size_ = std::fread(mem, sizeof(Ref), size, file);
+	    data.data_ = mem;
+	    std::fclose(file);
+	  }
+	else
+	  {
+	    __builtin_fprintf(
+		stderr,
+		"%s:%d: the reference data %s does not exist in the current "
+		"working directory.\n",
+		__FILE__, __LINE__, filename<Fun, T>().c_str());
+	    __builtin_abort();
+	  }
+      }
+    return data;
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h
new file mode 100644
index 00000000000..e9516537e60
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/metahelpers.h
@@ -0,0 +1,164 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef VC_TESTS_METAHELPERS_H_
+#define VC_TESTS_METAHELPERS_H_
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace vir
+{
+  namespace test
+  {
+    template <class A, class B, class Op>
+      constexpr bool
+      operator_is_substitution_failure_impl(float)
+      { return true; }
+
+    template <class A, class B, class Op>
+      constexpr typename std::conditional<true, bool, decltype(
+	  Op()(std::declval<A>(), std::declval<B>()))>::type
+      operator_is_substitution_failure_impl(int)
+      { return false; }
+
+    template <class... Ts>
+      constexpr bool
+      operator_is_substitution_failure()
+      { return operator_is_substitution_failure_impl<Ts...>(int()); }
+
+    template <class... Args, class F>
+      constexpr auto
+      sfinae_is_callable_impl(int, F &&f) -> typename std::conditional<
+	true, std::true_type,
+	decltype(std::forward<F>(f)(std::declval<Args>()...))>::type;
+
+    template <class... Args, class F>
+      constexpr std::false_type
+      sfinae_is_callable_impl(float, const F &);
+
+    template <class... Args, class F>
+      constexpr bool
+      sfinae_is_callable(F &&)
+      {
+	return decltype(
+	    sfinae_is_callable_impl<Args...>(int(), std::declval<F>()))::value;
+      }
+
+    template <class... Args, class F>
+      constexpr auto sfinae_is_callable_t(F &&f)
+	-> decltype(sfinae_is_callable_impl<Args...>(int(), std::declval<F>()));
+
+    template <class A, class B>
+      constexpr bool
+      has_less_bits()
+      { return std::__digits_v<A> < std::__digits_v<B>; }
+
+  }  // namespace test
+}  // namespace vir
+
+struct assignment
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() = std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) = std::forward<B>(b)))
+    { return std::forward<A>(a) = std::forward<B>(b); }
+};
+
+struct bit_shift_left
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() << std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) << std::forward<B>(b)))
+    { return std::forward<A>(a) << std::forward<B>(b); }
+};
+
+struct bit_shift_right
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() >> std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) >> std::forward<B>(b)))
+    { return std::forward<A>(a) >> std::forward<B>(b); }
+};
+
+struct assign_modulus
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() %= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) %= std::forward<B>(b)))
+    { return std::forward<A>(a) %= std::forward<B>(b); }
+};
+
+struct assign_bit_and
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() &= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) &= std::forward<B>(b)))
+    { return std::forward<A>(a) &= std::forward<B>(b); }
+};
+
+struct assign_bit_or
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() |= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) |= std::forward<B>(b)))
+    { return std::forward<A>(a) |= std::forward<B>(b); }
+};
+
+struct assign_bit_xor
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() ^= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) ^= std::forward<B>(b)))
+    { return std::forward<A>(a) ^= std::forward<B>(b); }
+};
+
+struct assign_bit_shift_left
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() <<= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) <<= std::forward<B>(b)))
+    { return std::forward<A>(a) <<= std::forward<B>(b); }
+};
+
+struct assign_bit_shift_right
+{
+  template <class A, class B>
+    constexpr decltype(std::declval<A>() >>= std::declval<B>())
+    operator()(A &&a, B &&b) const noexcept(noexcept(
+	std::forward<A>(a) >>= std::forward<B>(b)))
+    { return std::forward<A>(a) >>= std::forward<B>(b); }
+};
+
+template <class A, class B, class Op = std::plus<>>
+  constexpr bool is_substitution_failure
+    = vir::test::operator_is_substitution_failure<A, B, Op>();
+
+using vir::test::sfinae_is_callable;
+
+using vir::test::has_less_bits;
+
+#endif  // VC_TESTS_METAHELPERS_H_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h
new file mode 100644
index 00000000000..a221708df39
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/simd_view.h
@@ -0,0 +1,121 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef VC_TESTS_SIMD_VIEW_H_
+#define VC_TESTS_SIMD_VIEW_H_
+
+#include <experimental/simd>
+
+_GLIBCXX_SIMD_BEGIN_NAMESPACE
+
+namespace experimental
+{
+  namespace imported_begin_end
+  {
+    using std::begin;
+    using std::end;
+
+    template <class T>
+      using begin_type = decltype(begin(std::declval<T>()));
+
+    template <class T>
+      using end_type = decltype(end(std::declval<T>()));
+  }  // namespace imported_begin_end
+
+  template <class V, class It, class End>
+    class viewer
+    {
+      It it;
+      const End end;
+
+      template <class F>
+	void
+	for_each_impl(F &&fun, std::index_sequence<0, 1, 2>)
+	{
+	  for (; it + V::size() <= end; it += V::size())
+	    {
+	      fun(V([&](auto i) { return std::get<0>(it[i].as_tuple()); }),
+		  V([&](auto i) { return std::get<1>(it[i].as_tuple()); }),
+		  V([&](auto i) { return std::get<2>(it[i].as_tuple()); }));
+	    }
+	  if (it != end)
+	    {
+	      fun(V([&](auto i)
+	      {
+		auto ii = it + i < end ? i + 0 : 0;
+		return std::get<0>(it[ii].as_tuple());
+	      }),
+		  V([&](auto i) {
+		    auto ii = it + i < end ? i + 0 : 0;
+		    return std::get<1>(it[ii].as_tuple());
+		  }),
+		  V([&](auto i) {
+		    auto ii = it + i < end ? i + 0 : 0;
+		    return std::get<2>(it[ii].as_tuple());
+		  }));
+	    }
+	}
+
+      template <class F>
+	void
+	for_each_impl(F &&fun, std::index_sequence<0, 1>)
+	{
+	  for (; it + V::size() <= end; it += V::size())
+	    {
+	      fun(V([&](auto i) { return std::get<0>(it[i].as_tuple()); }),
+		  V([&](auto i) { return std::get<1>(it[i].as_tuple()); }));
+	    }
+	  if (it != end)
+	    {
+	      fun(V([&](auto i) {
+		auto ii = it + i < end ? i + 0 : 0;
+		return std::get<0>(it[ii].as_tuple());
+	      }),
+		  V([&](auto i) {
+		    auto ii = it + i < end ? i + 0 : 0;
+		    return std::get<1>(it[ii].as_tuple());
+		  }));
+	    }
+	}
+
+    public:
+      viewer(It _it, End _end)
+      : it(_it), end(_end) {}
+
+      template <class F>
+	void
+	for_each(F &&fun)
+	{
+	  constexpr size_t N
+	    = std::tuple_size<std::decay_t<decltype(it->as_tuple())>>::value;
+	  for_each_impl(std::forward<F>(fun), std::make_index_sequence<N>());
+	}
+    };
+
+  template <class V, class Cont>
+    viewer<V, imported_begin_end::begin_type<const Cont &>,
+	   imported_begin_end::end_type<const Cont &>>
+    simd_view(const Cont &data)
+    {
+      using std::begin;
+      using std::end;
+      return {begin(data), end(data)};
+    }
+}  // namespace experimental
+_GLIBCXX_SIMD_END_NAMESPACE
+
+#endif  // VC_TESTS_SIMD_VIEW_H_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h
new file mode 100644
index 00000000000..01988aef327
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/test_values.h
@@ -0,0 +1,383 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/simd>
+#include <initializer_list>
+#include <random>
+#include <cfenv>
+
+template <class T, class A>
+  std::experimental::simd<T, A>
+  iif(std::experimental::simd_mask<T, A> k,
+      const typename std::experimental::simd_mask<T, A>::simd_type& t,
+      const std::experimental::simd<T, A>& f)
+  {
+    auto r = f;
+    where(k, r) = t;
+    return r;
+  }
+
+template <class V>
+  V
+  epilogue_load(const typename V::value_type* mem, const std::size_t size)
+  {
+    const int rem = size % V::size();
+    return where(V([](int i) { return i; }) < rem, V(0))
+	     .copy_from(mem + size / V::size() * V::size(),
+			std::experimental::element_aligned);
+  }
+
+template <class V, class... F>
+  void
+  test_values(const std::initializer_list<typename V::value_type>& inputs,
+	      F&&... fun_pack)
+  {
+    for (auto it = inputs.begin(); it + V::size() <= inputs.end();
+	 it += V::size())
+      {
+	[](auto...) {
+	}((fun_pack(V(&it[0], std::experimental::element_aligned)), 0)...);
+      }
+    [](auto...) {
+    }((fun_pack(epilogue_load<V>(inputs.begin(), inputs.size())), 0)...);
+  }
+
+template <class V>
+  struct RandomValues
+  {
+    using T = typename V::value_type;
+    static constexpr bool isfp = std::is_floating_point_v<T>;
+    const std::size_t count;
+
+    std::conditional_t<std::is_floating_point_v<T>,
+		       std::uniform_real_distribution<T>,
+		       std::uniform_int_distribution<T>>
+      dist;
+
+    const bool uniform;
+
+    const T abs_max = std::__finite_max_v<T>;
+
+    RandomValues(std::size_t count_, T min, T max)
+    : count(count_), dist(min, max), uniform(true)
+    {
+      if constexpr (std::is_floating_point_v<T>)
+	VERIFY(max - min <= std::__finite_max_v<T>);
+    }
+
+    RandomValues(std::size_t count_)
+    : count(count_), dist(isfp ? 1 : std::__finite_min_v<T>,
+			  isfp ? 2 : std::__finite_max_v<T>),
+      uniform(!isfp)
+    {}
+
+    RandomValues(std::size_t count_, T abs_max_)
+    : count(count_), dist(isfp ? 1 : -abs_max_, isfp ? 2 : abs_max_),
+      uniform(!isfp), abs_max(abs_max_)
+    {}
+
+    template <typename URBG>
+      V
+      operator()(URBG& gen)
+      {
+	if constexpr (!isfp)
+	  return V([&](int) { return dist(gen); });
+	else if (uniform)
+	  return V([&](int) { return dist(gen); });
+	else
+	  {
+	    auto exp_dist
+	      = std::normal_distribution<float>(0.f,
+						std::__max_exponent_v<T> * .5f);
+	    return V([&](int) {
+		     const T mant = dist(gen);
+		     T fp = 0;
+		     do {
+		       const int exp = exp_dist(gen);
+		       fp = std::ldexp(mant, exp);
+		     } while (fp >= abs_max || fp <= std::__denorm_min_v<T>);
+		     fp = gen() & 0x4 ? fp : -fp;
+		     return fp;
+		   });
+	  }
+      }
+  };
+
+static std::mt19937 g_mt_gen{0};
+
+template <class V, class... F>
+  void
+  test_values(const std::initializer_list<typename V::value_type>& inputs,
+	      RandomValues<V> random, F&&... fun_pack)
+  {
+    test_values<V>(inputs, fun_pack...);
+    for (size_t i = 0; i < (random.count + V::size() - 1) / V::size(); ++i)
+      {
+	[](auto...) {}((fun_pack(random(g_mt_gen)), 0)...);
+      }
+  }
+
+template <class V, class... F>
+  void
+  test_values_2arg(const std::initializer_list<typename V::value_type>& inputs,
+		   F&&... fun_pack)
+  {
+    for (auto scalar_it = inputs.begin(); scalar_it != inputs.end();
+	 ++scalar_it)
+      {
+	for (auto it = inputs.begin(); it + V::size() <= inputs.end();
+	     it += V::size())
+	  {
+	    [](auto...) {
+	    }((fun_pack(V(&it[0], std::experimental::element_aligned),
+			V(*scalar_it)),
+	       0)...);
+	  }
+	[](auto...) {
+	}((fun_pack(epilogue_load<V>(inputs.begin(), inputs.size()),
+		    V(*scalar_it)),
+	   0)...);
+      }
+  }
+
+template <class V, class... F>
+  void
+  test_values_2arg(const std::initializer_list<typename V::value_type>& inputs,
+		   RandomValues<V> random, F&&... fun_pack)
+  {
+    test_values_2arg<V>(inputs, fun_pack...);
+    for (size_t i = 0; i < (random.count + V::size() - 1) / V::size(); ++i)
+      {
+	[](auto...) {}((fun_pack(random(g_mt_gen), random(g_mt_gen)), 0)...);
+      }
+  }
+
+template <class V, class... F>
+  void
+  test_values_3arg(const std::initializer_list<typename V::value_type>& inputs,
+		   F&&... fun_pack)
+  {
+    for (auto scalar_it1 = inputs.begin(); scalar_it1 != inputs.end();
+	 ++scalar_it1)
+      {
+	for (auto scalar_it2 = inputs.begin(); scalar_it2 != inputs.end();
+	     ++scalar_it2)
+	  {
+	    for (auto it = inputs.begin(); it + V::size() <= inputs.end();
+		 it += V::size())
+	      {
+		[](auto...) {
+		}((fun_pack(V(&it[0], std::experimental::element_aligned),
+			    V(*scalar_it1), V(*scalar_it2)),
+		   0)...);
+	      }
+	    [](auto...) {
+	    }((fun_pack(epilogue_load<V>(inputs.begin(), inputs.size()),
+			V(*scalar_it1), V(*scalar_it2)),
+	       0)...);
+	  }
+      }
+  }
+
+template <class V, class... F>
+  void
+  test_values_3arg(const std::initializer_list<typename V::value_type>& inputs,
+		   RandomValues<V> random, F&&... fun_pack)
+  {
+    test_values_3arg<V>(inputs, fun_pack...);
+    for (size_t i = 0; i < (random.count + V::size() - 1) / V::size(); ++i)
+      {
+	[](auto...) {
+	}((fun_pack(random(g_mt_gen), random(g_mt_gen), random(g_mt_gen)),
+	   0)...);
+      }
+  }
+
+#if __GCC_IEC_559 < 2
+// Without IEC559 we consider -0, subnormals, +/-inf, and all NaNs to be
+// invalid (potential UB when used or "produced"). This can't use isnormal (or
+// any other classification function), since they know about the UB.
+template <class V>
+  typename V::mask_type
+  isvalid(V x)
+  {
+    using namespace std::experimental::parallelism_v2;
+    using namespace std::experimental::parallelism_v2::__proposed;
+    using T = typename V::value_type;
+    if constexpr (sizeof(T) <= sizeof(double))
+      {
+	using I = rebind_simd_t<__int_for_sizeof_t<T>, V>;
+	const I abs_x = __bit_cast<I>(abs(x));
+	const I min = __bit_cast<I>(V(std::__norm_min_v<T>));
+	const I max = __bit_cast<I>(V(std::__finite_max_v<T>));
+	return static_simd_cast<typename V::mask_type>(
+		 __bit_cast<I>(x) == 0 || (abs_x >= min && abs_x <= max));
+      }
+    else
+      {
+	const V abs_x = abs(x);
+	const V min = std::__norm_min_v<T>;
+	// Make max non-const static to inhibit constprop. Otherwise the
+	// compiler might decide `abs_x <= max` is constexpr true, by definition
+	// (-ffinite-math-only)
+	static V max = std::__finite_max_v<T>;
+	return (x == 0 && copysign(V(1), x) == V(1))
+		 || (abs_x >= min && abs_x <= max);
+      }
+  }
+
+#define MAKE_TESTER_2(name_, reference_)                                       \
+  [&](auto... inputs) {                                                        \
+    ((where(!isvalid(inputs), inputs) = 1), ...);                              \
+    const auto totest = name_(inputs...);                                      \
+    using R = std::remove_const_t<decltype(totest)>;                           \
+    auto&& expected = [&](const auto&... vs) -> const R {                      \
+      R tmp = {};                                                              \
+      for (std::size_t i = 0; i < R::size(); ++i)                              \
+	tmp[i] = reference_(vs[i]...);                                         \
+      return tmp;                                                              \
+    };                                                                         \
+    const R expect1 = expected(inputs...);                                     \
+    if constexpr (std::is_floating_point_v<typename R::value_type>)            \
+      {                                                                        \
+	((where(!isvalid(expect1), inputs) = 1), ...);                         \
+	const R expect2 = expected(inputs...);                                 \
+	((FUZZY_COMPARE(name_(inputs...), expect2) << "\ninputs = ")           \
+	 << ... << inputs);                                                    \
+      }                                                                        \
+    else                                                                       \
+      ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(")                 \
+       << ... << inputs)                                                       \
+	<< ")";                                                                \
+  }
+
+#define MAKE_TESTER_NOFPEXCEPT(name_)                                          \
+  [&](auto... inputs) {                                                        \
+    ((where(!isvalid(inputs), inputs) = 1), ...);                              \
+    using R = std::remove_const_t<decltype(name_(inputs...))>;                 \
+    auto&& expected = [&](const auto&... vs) -> const R {                      \
+      R tmp = {};                                                              \
+      for (std::size_t i = 0; i < R::size(); ++i)                              \
+	tmp[i] = std::name_(vs[i]...);                                         \
+      return tmp;                                                              \
+    };                                                                         \
+    const R expect1 = expected(inputs...);                                     \
+    if constexpr (std::is_floating_point_v<typename R::value_type>)            \
+      {                                                                        \
+	((where(!isvalid(expect1), inputs) = 1), ...);                         \
+	std::feclearexcept(FE_ALL_EXCEPT);                                     \
+	asm volatile("");                                                      \
+	auto totest = name_(inputs...);                                        \
+	asm volatile("");                                                      \
+	((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(")     \
+	 << ... << inputs)                                                     \
+	  << ")";                                                              \
+	const R expect2 = expected(inputs...);                                 \
+	std::feclearexcept(FE_ALL_EXCEPT);                                     \
+	asm volatile("");                                                      \
+	totest = name_(inputs...);                                             \
+	asm volatile("");                                                      \
+	((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(")     \
+	 << ... << inputs)                                                     \
+	  << ")";                                                              \
+	((FUZZY_COMPARE(totest, expect2) << "\n" #name_ "(") << ... << inputs) \
+	  << ")";                                                              \
+      }                                                                        \
+    else                                                                       \
+      {                                                                        \
+	std::feclearexcept(FE_ALL_EXCEPT);                                     \
+	asm volatile("");                                                      \
+	auto totest = name_(inputs...);                                        \
+	asm volatile("");                                                      \
+	((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(")     \
+	 << ... << inputs)                                                     \
+	  << ")";                                                              \
+	((COMPARE(totest, expect1) << "\n" #name_ "(") << ... << inputs)       \
+	  << ")";                                                              \
+      }                                                                        \
+  }
+
+#else
+
+#define MAKE_TESTER_2(name_, reference_)                                       \
+  [&](auto... inputs) {                                                        \
+    const auto totest = name_(inputs...);                                      \
+    using R = std::remove_const_t<decltype(totest)>;                           \
+    auto&& expected = [&](const auto&... vs) -> const R {                      \
+      R tmp = {};                                                              \
+      for (std::size_t i = 0; i < R::size(); ++i)                              \
+	tmp[i] = reference_(vs[i]...);                                         \
+      return tmp;                                                              \
+    };                                                                         \
+    const R expect1 = expected(inputs...);                                     \
+    if constexpr (std::is_floating_point_v<typename R::value_type>)            \
+      {                                                                        \
+	((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(")                \
+	 << ... << inputs)                                                     \
+	  << ") = " << totest << " != " << expect1;                            \
+	((where(isnan(expect1), inputs) = 0), ...);                            \
+	((FUZZY_COMPARE(name_(inputs...), expected(inputs...))                 \
+	  << "\nclean = ")                                                     \
+	 << ... << inputs);                                                    \
+      }                                                                        \
+    else                                                                       \
+      ((COMPARE(name_(inputs...), expect1) << "\n" #name_ "(")                 \
+       << ... << inputs)                                                       \
+	<< ")";                                                                \
+  }
+
+#define MAKE_TESTER_NOFPEXCEPT(name_)                                          \
+  [&](auto... inputs) {                                                        \
+    std::feclearexcept(FE_ALL_EXCEPT);                                         \
+    auto totest = name_(inputs...);                                            \
+    ((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(")         \
+     << ... << inputs)                                                         \
+      << ")";                                                                  \
+    using R = std::remove_const_t<decltype(totest)>;                           \
+    auto&& expected = [&](const auto&... vs) -> const R {                      \
+      R tmp = {};                                                              \
+      for (std::size_t i = 0; i < R::size(); ++i)                              \
+	tmp[i] = std::name_(vs[i]...);                                         \
+      return tmp;                                                              \
+    };                                                                         \
+    const R expect1 = expected(inputs...);                                     \
+    if constexpr (std::is_floating_point_v<typename R::value_type>)            \
+      {                                                                        \
+	((COMPARE(isnan(totest), isnan(expect1)) << #name_ "(")                \
+	 << ... << inputs)                                                     \
+	  << ") = " << totest << " != " << expect1;                            \
+	((where(isnan(expect1), inputs) = 0), ...);                            \
+	const R expect2 = expected(inputs...);                                 \
+	std::feclearexcept(FE_ALL_EXCEPT);                                     \
+	asm volatile("");                                                      \
+	totest = name_(inputs...);                                             \
+	asm volatile("");                                                      \
+	((COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0) << "\n" #name_ "(")     \
+	 << ... << inputs)                                                     \
+	  << ")";                                                              \
+	FUZZY_COMPARE(totest, expect2);                                        \
+      }                                                                        \
+    else                                                                       \
+      {                                                                        \
+	((COMPARE(totest, expect1) << "\n" #name_ "(") << ... << inputs)       \
+	  << ")";                                                              \
+      }                                                                        \
+  }
+
+#endif
+
+#define MAKE_TESTER(name_) MAKE_TESTER_2(name_, std::name_)
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h
new file mode 100644
index 00000000000..3b6966dd85d
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/ulp.h
@@ -0,0 +1,101 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef ULP_H
+#define ULP_H
+
+#include <cmath>
+#include <experimental/simd>
+#include <type_traits>
+#include <cfenv>
+
+namespace vir {
+  namespace test {
+    template <typename T, typename R = typename T::value_type>
+      R
+      value_type_impl(int);
+
+    template <typename T>
+      T
+      value_type_impl(float);
+
+    template <typename T>
+      using value_type_t = decltype(value_type_impl<T>(int()));
+
+    template <typename T>
+      inline T
+      ulp_distance(const T& val_, const T& ref_)
+      {
+        if constexpr (std::is_floating_point_v<value_type_t<T>>)
+          {
+            const int fp_exceptions = std::fetestexcept(FE_ALL_EXCEPT);
+            T val = val_;
+            T ref = ref_;
+
+            T diff = T();
+
+            using std::abs;
+            using std::fpclassify;
+            using std::frexp;
+            using std::isnan;
+            using std::isinf;
+            using std::ldexp;
+            using std::max;
+            using std::experimental::where;
+            using TT = value_type_t<T>;
+
+            where(ref == 0, val) = abs(val);
+            where(ref == 0, diff) = 1;
+            where(ref == 0, ref) = std::__norm_min_v<TT>;
+            where(isinf(ref) && ref == val, ref)
+              = 0; // where(val_ == ref_) = 0 below will fix it up
+
+            where(val == 0, ref) = abs(ref);
+            where(val == 0, diff) += 1;
+            where(val == 0, val) = std::__norm_min_v<TT>;
+
+            using I = decltype(fpclassify(std::declval<T>()));
+            I exp = {};
+            frexp(ref, &exp);
+            // lower bound for exp must be min_exponent to scale the resulting
+            // difference from a denormal correctly
+            exp = max(exp, I(std::__min_exponent_v<TT>));
+            diff += ldexp(abs(ref - val), std::__digits_v<TT> - exp);
+            where(val_ == ref_ || (isnan(val_) && isnan(ref_)), diff) = T();
+            std::feclearexcept(FE_ALL_EXCEPT ^ fp_exceptions);
+            return diff;
+          }
+        else
+          {
+            if (val_ > ref_)
+              return val_ - ref_;
+            else
+              return ref_ - val_;
+          }
+      }
+
+    template <typename T>
+      inline T
+      ulp_distance_signed(const T& _val, const T& _ref)
+      {
+        using std::copysign;
+        return copysign(ulp_distance(_val, _ref), _val - _ref);
+      }
+  } // namespace test
+} // namespace vir
+
+#endif // ULP_H
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h
new file mode 100644
index 00000000000..5da47b35536
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/bits/verify.h
@@ -0,0 +1,353 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef TESTS_BITS_VERIFY_H_
+#define TESTS_BITS_VERIFY_H_
+
+#include <experimental/simd>
+#include <sstream>
+#include <iomanip>
+#include "ulp.h"
+
+#ifdef _GLIBCXX_SIMD_HAVE_NEON
+// work around PR89357:
+#define alignas(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+using schar = signed char;
+using uchar = unsigned char;
+using ushort = unsigned short;
+using uint = unsigned int;
+using ulong = unsigned long;
+using llong = long long;
+using ullong = unsigned long long;
+using ldouble = long double;
+using wchar = wchar_t;
+using char16 = char16_t;
+using char32 = char32_t;
+
+template <class T>
+  T
+  make_value_unknown(const T& x)
+  {
+    if constexpr (std::is_constructible_v<T, const volatile T&>)
+      {
+	const volatile T& y = x;
+	return y;
+      }
+    else
+      {
+	T y = x;
+	asm("" : "+m"(y));
+	return y;
+      }
+  }
+
+class verify
+{
+  const bool m_failed = false;
+
+  template <typename T,
+	    typename = decltype(std::declval<std::stringstream&>()
+				<< std::declval<const T&>())>
+    void
+    print(const T& x, int) const
+    {
+      std::stringstream ss;
+      ss << x;
+      __builtin_fprintf(stderr, "%s", ss.str().c_str());
+    }
+
+  template <typename T>
+    void
+    print(const T& x, ...) const
+    {
+      if constexpr (std::experimental::is_simd_v<T>)
+	{
+	  std::stringstream ss;
+	  if constexpr (std::is_floating_point_v<typename T::value_type>)
+	    {
+	      ss << '(' << x[0] << " == " << std::hexfloat << x[0]
+		<< std::defaultfloat << ')';
+	      for (unsigned i = 1; i < x.size(); ++i)
+		{
+		  ss << (i % 4 == 0 ? ",\n(" : ", (") << x[i]
+		    << " == " << std::hexfloat << x[i] << std::defaultfloat
+		    << ')';
+		}
+	    }
+	  else
+	    {
+	      ss << +x[0];
+	      for (unsigned i = 1; i < x.size(); ++i)
+		{
+		  ss << ", " << +x[i];
+		}
+	    }
+	  __builtin_fprintf(stderr, "%s", ss.str().c_str());
+	}
+      else if constexpr (std::experimental::is_simd_mask_v<T>)
+	{
+	  __builtin_fprintf(stderr, (x[0] ? "[1" : "[0"));
+	  for (unsigned i = 1; i < x.size(); ++i)
+	    {
+	      __builtin_fprintf(stderr, (x[i] ? "1" : "0"));
+	    }
+	  __builtin_fprintf(stderr, "]");
+	}
+      else
+	{
+	  print_hex(&x, sizeof(T));
+	}
+    }
+
+  void
+  print_hex(const void* x, std::size_t n) const
+  {
+    __builtin_fprintf(stderr, "0x");
+    const auto* bytes = static_cast<const unsigned char*>(x);
+    for (std::size_t i = 0; i < n; ++i)
+      {
+	__builtin_fprintf(stderr, (i && i % 4 == 0) ? "'%02x" : "%02x",
+			  bytes[i]);
+      }
+  }
+
+public:
+  template <typename... Ts>
+    verify(bool ok, size_t ip, const char* file, const int line,
+	   const char* func, const char* cond, const Ts&... extra_info)
+    : m_failed(!ok)
+    {
+      if (m_failed)
+	{
+	  __builtin_fprintf(stderr, "%s:%d: (%s):\nInstruction Pointer: %x\n"
+				    "Assertion '%s' failed.\n",
+			    file, line, func, ip, cond);
+	  (print(extra_info, int()), ...);
+	}
+    }
+
+  ~verify()
+  {
+    if (m_failed)
+      {
+	__builtin_fprintf(stderr, "\n");
+	__builtin_abort();
+      }
+  }
+
+  template <typename T>
+    const verify&
+    operator<<(const T& x) const
+    {
+      if (m_failed)
+	{
+	  print(x, int());
+	}
+      return *this;
+    }
+
+  template <typename... Ts>
+    const verify&
+    on_failure(const Ts&... xs) const
+    {
+      if (m_failed)
+	(print(xs, int()), ...);
+      return *this;
+    }
+
+  [[gnu::always_inline]] static inline size_t
+  get_ip()
+  {
+    size_t _ip = 0;
+#ifdef __x86_64__
+    asm volatile("lea 0(%%rip),%0" : "=r"(_ip));
+#elif defined __i386__
+    asm volatile("1: movl $1b,%0" : "=r"(_ip));
+#elif defined __arm__
+    asm volatile("mov %0,pc" : "=r"(_ip));
+#elif defined __aarch64__
+    asm volatile("adr %0,." : "=r"(_ip));
+#endif
+    return _ip;
+  }
+};
+
+#if __FLT_EVAL_METHOD__ != 0
+template <typename T>
+  [[gnu::always_inline]] inline decltype(auto)
+  force_fp_truncation(const T& x)
+  {
+    namespace stdx = std::experimental;
+    if constexpr (stdx::is_simd_v<T>)
+      {
+	using U = typename T::value_type;
+	if constexpr (std::is_floating_point_v<typename T::value_type>
+		      && sizeof(U) <= 8 && (sizeof(T) < 16 || std::is_same_v<
+		  T, stdx::fixed_size_simd<U, T::size()>>))
+	  {
+	    T y = x;
+	    asm("" : "+m"(y));
+	    return y;
+	  }
+	else
+	  return x;
+      }
+    else if constexpr (std::is_floating_point_v<T> && sizeof(T) <= 8)
+      {
+	T y = x;
+	asm("" : "+m"(y));
+	return y;
+      }
+    else
+      return x;
+  }
+
+#define COMPARE(_a, _b)                                                        \
+  [&](auto&& _aa, auto&& _bb) {                                                \
+    return verify(std::experimental::all_of(_aa == _bb), verify::get_ip(),     \
+		  __FILE__, __LINE__, __PRETTY_FUNCTION__,                     \
+		  "all_of(" #_a " == " #_b ")", #_a " = ", _aa,                \
+		  "\n" #_b " = ", _bb);                                        \
+  }(force_fp_truncation(_a), force_fp_truncation(_b))
+#else
+#define COMPARE(_a, _b)                                                        \
+  [&](auto&& _aa, auto&& _bb) {                                                \
+    return verify(std::experimental::all_of(_aa == _bb), verify::get_ip(),     \
+		  __FILE__, __LINE__, __PRETTY_FUNCTION__,                     \
+		  "all_of(" #_a " == " #_b ")", #_a " = ", _aa,                \
+		  "\n" #_b " = ", _bb);                                        \
+  }((_a), (_b))
+#endif
+
+#define VERIFY(_test)                                                          \
+  verify(_test, verify::get_ip(), __FILE__, __LINE__, __PRETTY_FUNCTION__,     \
+	 #_test)
+
+  // ulp_distance_signed can raise FP exceptions and thus must be conditionally
+  // executed
+#define ULP_COMPARE(_a, _b, _allowed_distance)                                 \
+  [&](auto&& _aa, auto&& _bb) {                                                \
+    const bool success = std::experimental::all_of(                            \
+      vir::test::ulp_distance(_aa, _bb) <= (_allowed_distance));               \
+    return verify(success, verify::get_ip(), __FILE__, __LINE__,               \
+		  __PRETTY_FUNCTION__, "all_of(" #_a " ~~ " #_b ")",           \
+		  #_a " = ", _aa, "\n" #_b " = ", _bb, "\ndistance = ",        \
+		  success ? 0 : vir::test::ulp_distance_signed(_aa, _bb));     \
+  }((_a), (_b))
+
+namespace vir {
+  namespace test
+  {
+    template <typename T>
+      inline T _S_fuzzyness = 0;
+
+    template <typename T>
+      void
+      setFuzzyness(T x)
+      { _S_fuzzyness<T> = x; }
+  } // namespace test
+} // namespace vir
+
+#define FUZZY_COMPARE(_a, _b)                                                  \
+  ULP_COMPARE(                                                                 \
+    _a, _b,                                                                    \
+    vir::test::_S_fuzzyness<vir::test::value_type_t<decltype((_a) + (_b))>>)
+
+template <typename V>
+  void
+  test();
+
+template <typename V>
+  void
+  invoke_test(...)
+  {}
+
+template <typename V, typename = decltype(V())>
+  void
+  invoke_test(int)
+  {
+    test<V>();
+    __builtin_fprintf(stderr, "PASS: %s\n", __PRETTY_FUNCTION__);
+  }
+
+template <class T>
+  void
+  iterate_abis()
+  {
+    using namespace std::experimental::parallelism_v2;
+#ifndef EXTENDEDTESTS
+    invoke_test<simd<T, simd_abi::scalar>>(int());
+    invoke_test<simd<T, simd_abi::_VecBuiltin<16>>>(int());
+    invoke_test<simd<T, simd_abi::_VecBltnBtmsk<64>>>(int());
+#elif EXTENDEDTESTS == 0
+    invoke_test<simd<T, simd_abi::_VecBuiltin<8>>>(int());
+    invoke_test<simd<T, simd_abi::_VecBuiltin<12>>>(int());
+    invoke_test<simd<T, simd_abi::_VecBuiltin<24>>>(int());
+    invoke_test<simd<T, simd_abi::_VecBuiltin<32>>>(int());
+    invoke_test<simd<T, simd_abi::_VecBltnBtmsk<56>>>(int());
+#elif EXTENDEDTESTS == 1
+    invoke_test<simd<T, simd_abi::fixed_size<8>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<16>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<24>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<32>>>(int());
+#elif EXTENDEDTESTS == 2
+    invoke_test<simd<T, simd_abi::fixed_size<1>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<9>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<17>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<25>>>(int());
+#elif EXTENDEDTESTS == 3
+    invoke_test<simd<T, simd_abi::fixed_size<2>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<10>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<18>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<26>>>(int());
+#elif EXTENDEDTESTS == 4
+    invoke_test<simd<T, simd_abi::fixed_size<3>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<19>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<11>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<27>>>(int());
+#elif EXTENDEDTESTS == 5
+    invoke_test<simd<T, simd_abi::fixed_size<4>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<12>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<20>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<28>>>(int());
+#elif EXTENDEDTESTS == 6
+    invoke_test<simd<T, simd_abi::fixed_size<5>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<13>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<21>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<29>>>(int());
+#elif EXTENDEDTESTS == 7
+    invoke_test<simd<T, simd_abi::fixed_size<6>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<14>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<22>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<30>>>(int());
+#elif EXTENDEDTESTS == 8
+    invoke_test<simd<T, simd_abi::fixed_size<7>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<15>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<23>>>(int());
+    invoke_test<simd<T, simd_abi::fixed_size<31>>>(int());
+#endif
+  }
+
+int main()
+{
+  iterate_abis<_GLIBCXX_SIMD_TESTTYPE>();
+  return 0;
+}
+
+#endif  // TESTS_BITS_VERIFY_H_
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc
new file mode 100644
index 00000000000..c107de3380b
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/broadcast.cc
@@ -0,0 +1,104 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+enum unscoped_enum
+{ foo };
+
+enum class scoped_enum
+{ bar };
+
+struct convertible
+{
+  operator int();
+  operator float();
+};
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    VERIFY(std::experimental::is_simd_v<V>);
+    VERIFY(std::experimental::is_abi_tag_v<typename V::abi_type>);
+
+    {
+      V x;     // not initialized
+      x = V{}; // default broadcasts 0
+      COMPARE(x, V(0));
+      COMPARE(x, V());
+      COMPARE(x, V{});
+      x = V(); // default broadcasts 0
+      COMPARE(x, V(0));
+      COMPARE(x, V());
+      COMPARE(x, V{});
+      x = 0;
+      COMPARE(x, V(0));
+      COMPARE(x, V());
+      COMPARE(x, V{});
+
+      for (std::size_t i = 0; i < V::size(); ++i)
+	{
+	  COMPARE(T(x[i]), T(0)) << "i = " << i;
+	  COMPARE(x[i], T(0)) << "i = " << i;
+	}
+    }
+
+    V x = 3;
+    V y = T(0);
+    for (std::size_t i = 0; i < V::size(); ++i)
+      {
+	COMPARE(x[i], T(3)) << "i = " << i;
+	COMPARE(y[i], T(0)) << "i = " << i;
+      }
+    y = 3;
+    COMPARE(x, y);
+
+    VERIFY(!(is_substitution_failure<V&, unscoped_enum, assignment>) );
+    VERIFY((is_substitution_failure<V&, scoped_enum, assignment>) );
+    COMPARE((is_substitution_failure<V&, convertible, assignment>),
+	    (!std::is_convertible<convertible, T>::value));
+    COMPARE((is_substitution_failure<V&, long double, assignment>),
+	    (sizeof(long double) > sizeof(T) || std::is_integral<T>::value));
+    COMPARE((is_substitution_failure<V&, double, assignment>),
+	    (sizeof(double) > sizeof(T) || std::is_integral<T>::value));
+    COMPARE((is_substitution_failure<V&, float, assignment>),
+	    (sizeof(float) > sizeof(T) || std::is_integral<T>::value));
+    COMPARE((is_substitution_failure<V&, long long, assignment>),
+	    (has_less_bits<T, long long>() || std::is_unsigned<T>::value));
+    COMPARE((is_substitution_failure<V&, unsigned long long, assignment>),
+	    (has_less_bits<T, unsigned long long>()));
+    COMPARE((is_substitution_failure<V&, long, assignment>),
+	    (has_less_bits<T, long>() || std::is_unsigned<T>::value));
+    COMPARE((is_substitution_failure<V&, unsigned long, assignment>),
+	    (has_less_bits<T, unsigned long>()));
+    // int broadcast *always* works:
+    VERIFY(!(is_substitution_failure<V&, int, assignment>) );
+    // uint broadcast works for any unsigned T:
+    COMPARE((is_substitution_failure<V&, unsigned int, assignment>),
+	    (!std::is_unsigned<T>::value && has_less_bits<T, unsigned int>()));
+    COMPARE((is_substitution_failure<V&, short, assignment>),
+	    (has_less_bits<T, short>() || std::is_unsigned<T>::value));
+    COMPARE((is_substitution_failure<V&, unsigned short, assignment>),
+	    (has_less_bits<T, unsigned short>()));
+    COMPARE((is_substitution_failure<V&, signed char, assignment>),
+	    (has_less_bits<T, signed char>() || std::is_unsigned<T>::value));
+    COMPARE((is_substitution_failure<V&, unsigned char, assignment>),
+	    (has_less_bits<T, unsigned char>()));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc
new file mode 100644
index 00000000000..df169e100de
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/casts.cc
@@ -0,0 +1,169 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+using std::experimental::static_simd_cast;
+
+template <class T, size_t N>
+  struct gen_cast
+  {
+    std::array<T, N> data;
+
+    template <class V>
+      gen_cast(const V& v)
+      {
+	for (size_t i = 0; i < V::size(); ++i)
+	  {
+	    data[i] = static_cast<T>(v[i]);
+	  }
+      }
+
+    template <class I>
+      constexpr T
+      operator()(I)
+      { return data[I::value]; }
+  };
+
+template <class V, class To>
+  struct gen_seq_t
+  {
+    using From = typename V::value_type;
+    const size_t N = cvt_input_data<From, To>.size();
+    size_t offset = 0;
+
+    constexpr void
+    operator++()
+    { offset += V::size(); }
+
+    explicit constexpr operator bool() const
+    { return offset < N; }
+
+    template <class I>
+      constexpr From
+      operator()(I) const
+      {
+	size_t i = I::value + offset;
+	return i < N ? cvt_input_data<From, To>[i] : From(i);
+      }
+  };
+
+template <class To>
+  struct foo
+  {
+    template <class T>
+      auto
+      operator()(const T& v) -> decltype(simd_cast<To>(v));
+  };
+
+template <typename V, typename To>
+  void
+  casts()
+  {
+    using From = typename V::value_type;
+    constexpr auto N = V::size();
+    if constexpr (N <= std::experimental::simd_abi::max_fixed_size<To>)
+      {
+	using W = std::experimental::fixed_size_simd<To, N>;
+
+	if constexpr (std::is_integral_v<From>)
+	  {
+	    using A = typename V::abi_type;
+	    using TU = std::make_unsigned_t<From>;
+	    using TS = std::make_signed_t<From>;
+	    COMPARE(typeid(static_simd_cast<TU>(V())),
+		    typeid(std::experimental::simd<TU, A>));
+	    COMPARE(typeid(static_simd_cast<TS>(V())),
+		    typeid(std::experimental::simd<TS, A>));
+	  }
+
+	using is_simd_cast_allowed
+	  = decltype(vir::test::sfinae_is_callable_t<const V&>(foo<To>()));
+
+	COMPARE(is_simd_cast_allowed::value,
+		std::__digits<From>::value <= std::__digits<To>::value
+		  && std::__finite_max<From>::value
+		  <= std::__finite_max<To>::value
+		  && !(std::is_signed<From>::value
+		       && std::is_unsigned<To>::value));
+
+	if constexpr (is_simd_cast_allowed::value)
+	  {
+	    for (gen_seq_t<V, To> gen_seq; gen_seq; ++gen_seq)
+	      {
+		const V seq(gen_seq);
+		COMPARE(simd_cast<V>(seq), seq);
+		COMPARE(simd_cast<W>(seq), W(gen_cast<To, N>(seq)))
+		  << "seq = " << seq;
+		auto test = simd_cast<To>(seq);
+		// decltype(test) is not W if
+		// a) V::abi_type is not fixed_size and
+		// b.1) V::value_type and To are integral and of equal rank or
+		// b.2) V::value_type and To are equal
+		COMPARE(test, decltype(test)(gen_cast<To, N>(seq)));
+		if (std::is_same<To, From>::value)
+		  {
+		    COMPARE(typeid(decltype(test)), typeid(V));
+		  }
+	      }
+	  }
+
+	for (gen_seq_t<V, To> gen_seq; gen_seq; ++gen_seq)
+	  {
+	    const V seq(gen_seq);
+	    COMPARE(static_simd_cast<V>(seq), seq);
+	    COMPARE(static_simd_cast<W>(seq), W(gen_cast<To, N>(seq))) << '\n'
+	      << seq;
+	    auto test = static_simd_cast<To>(seq);
+	    // decltype(test) is not W if
+	    // a) V::abi_type is not fixed_size and
+	    // b.1) V::value_type and To are integral and of equal rank or
+	    // b.2) V::value_type and To are equal
+	    COMPARE(test, decltype(test)(gen_cast<To, N>(seq)));
+	    if (std::is_same<To, From>::value)
+	      {
+		COMPARE(typeid(decltype(test)), typeid(V));
+	      }
+	  }
+      }
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    casts<V, long double>();
+    casts<V, double>();
+    casts<V, float>();
+    casts<V, long long>();
+    casts<V, unsigned long long>();
+    casts<V, unsigned long>();
+    casts<V, long>();
+    casts<V, int>();
+    casts<V, unsigned int>();
+    casts<V, short>();
+    casts<V, unsigned short>();
+    casts<V, char>();
+    casts<V, signed char>();
+    casts<V, unsigned char>();
+    casts<V, char32_t>();
+    casts<V, char16_t>();
+    casts<V, wchar_t>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc
new file mode 100644
index 00000000000..eef26108f5f
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/fpclassify.cc
@@ -0,0 +1,106 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <cfenv>
+
+template <typename F>
+  auto
+  verify_no_fp_exceptions(F&& fun)
+  {
+    std::feclearexcept(FE_ALL_EXCEPT);
+    auto r = fun();
+    COMPARE(std::fetestexcept(FE_ALL_EXCEPT), 0);
+    return r;
+  }
+
+#define NOFPEXCEPT(...) verify_no_fp_exceptions([&]() { return __VA_ARGS__; })
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    using intv = std::experimental::fixed_size_simd<int, V::size()>;
+    constexpr T inf = std::__infinity_v<T>;
+    constexpr T denorm_min = std::__infinity_v<T>;
+    constexpr T nan = std::__quiet_NaN_v<T>;
+    constexpr T max = std::__finite_max_v<T>;
+    constexpr T norm_min = std::__norm_min_v<T>;
+    test_values<V>(
+      {0., 1., -1.,
+#if __GCC_IEC_559 >= 2
+       -0., inf, -inf, denorm_min, -denorm_min, nan,
+       norm_min * 0.9, -norm_min * 0.9,
+#endif
+       max, -max, norm_min, -norm_min
+      },
+      [](const V input) {
+	COMPARE(NOFPEXCEPT(isfinite(input)),
+		!V([&](auto i) { return std::isfinite(input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(isinf(input)),
+		!V([&](auto i) { return std::isinf(input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(isnan(input)),
+		!V([&](auto i) { return std::isnan(input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(isnormal(input)),
+		!V([&](auto i) { return std::isnormal(input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(signbit(input)),
+		!V([&](auto i) { return std::signbit(input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(isunordered(input, V())),
+		!V([&](auto i) { return std::isunordered(input[i], 0) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(isunordered(V(), input)),
+		!V([&](auto i) { return std::isunordered(0, input[i]) ? 0 : 1; }))
+	  << input;
+	COMPARE(NOFPEXCEPT(fpclassify(input)),
+		intv([&](auto i) { return std::fpclassify(input[i]); }))
+	  << input;
+      });
+#ifdef __SUPPORT_SNAN__
+    const V snan = std::__signaling_NaN_v<T>;
+    COMPARE(isfinite(snan),
+	    !V([&](auto i) { return std::isfinite(snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(isinf(snan), !V([&](auto i) { return std::isinf(snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(isnan(snan), !V([&](auto i) { return std::isnan(snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(isnormal(snan),
+	    !V([&](auto i) { return std::isnormal(snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(signbit(snan),
+	    !V([&](auto i) { return std::signbit(snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(isunordered(snan, V()),
+	    !V([&](auto i) { return std::isunordered(snan[i], 0) ? 0 : 1; }))
+      << snan;
+    COMPARE(isunordered(V(), snan),
+	    !V([&](auto i) { return std::isunordered(0, snan[i]) ? 0 : 1; }))
+      << snan;
+    COMPARE(fpclassify(snan),
+	    intv([&](auto i) { return std::fpclassify(snan[i]); }))
+      << snan;
+#endif
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc
new file mode 100644
index 00000000000..e2d90dd1e3f
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/frexp.cc
@@ -0,0 +1,85 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using int_v = std::experimental::fixed_size_simd<int, V::size()>;
+    using T = typename V::value_type;
+    constexpr auto denorm_min = std::__denorm_min_v<T>;
+    constexpr auto norm_min = std::__norm_min_v<T>;
+    constexpr auto max = std::__finite_max_v<T>;
+    constexpr auto nan = std::__quiet_NaN_v<T>;
+    constexpr auto inf = std::__infinity_v<T>;
+    test_values<V>(
+      {0, 0.25, 0.5, 1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+       20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 31, -0., -0.25, -0.5, -1,
+       -3, -4, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18,
+       -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -32, -31,
+#if __GCC_IEC_559 >= 2
+       denorm_min, -denorm_min, norm_min / 2, -norm_min / 2,
+#endif
+       max, -max, max * 0.123f, -max * 0.123f},
+      [](const V input) {
+	V expectedFraction;
+	const int_v expectedExponent([&](auto i) {
+	  int exp;
+	  expectedFraction[i] = std::frexp(input[i], &exp);
+	  return exp;
+	});
+	int_v exponent = {};
+	const V fraction = frexp(input, &exponent);
+	COMPARE(fraction, expectedFraction) << ", input = " << input
+	  << ", delta: " << fraction - expectedFraction;
+	COMPARE(exponent, expectedExponent)
+	  << "\ninput: " << input << ", fraction: " << fraction;
+      });
+#ifdef __STDC_IEC_559__
+    test_values<V>(
+      // If x is a NaN, a NaN is returned, and the value of *exp is unspecified.
+      //
+      // If x is positive  infinity  (negative  infinity),  positive  infinity
+      // (negative infinity) is returned, and the value of *exp is unspecified.
+      // This behavior is only guaranteed with C's Annex F when __STDC_IEC_559__
+      // is defined.
+      {nan, inf, -inf, denorm_min, denorm_min * 1.72, -denorm_min,
+       -denorm_min * 1.72, 0., -0., 1, -1},
+      [](const V input) {
+	const V expectedFraction([&](auto i) {
+	  int exp;
+	  return std::frexp(input[i], &exp);
+	});
+	int_v exponent = {};
+	const V fraction = frexp(input, &exponent);
+	COMPARE(isnan(fraction), isnan(expectedFraction))
+	  << fraction << ", input = " << input
+	  << ", delta: " << fraction - expectedFraction;
+	COMPARE(isinf(fraction), isinf(expectedFraction))
+	  << fraction << ", input = " << input
+	  << ", delta: " << fraction - expectedFraction;
+	COMPARE(signbit(fraction), signbit(expectedFraction))
+	  << fraction << ", input = " << input
+	  << ", delta: " << fraction - expectedFraction;
+      });
+#endif
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc
new file mode 100644
index 00000000000..221064dc476
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/generator.cc
@@ -0,0 +1,58 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <class V>
+  struct call_generator
+  {
+    template <class F>
+      auto
+      operator()(const F& f) -> decltype(V(f));
+  };
+
+using schar = signed char;
+using uchar = unsigned char;
+using ullong = unsigned long long;
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    V x([](int) { return T(1); });
+    COMPARE(x, V(1));
+    // unconditionally returns int from generator lambda
+    x = V([](int) { return 1; });
+    COMPARE(x, V(1));
+    x = V([](auto i) { return T(i); });
+    COMPARE(x, V([](T i) { return i; }));
+
+    VERIFY((// that int always works
+	sfinae_is_callable<int (&)(int)>(call_generator<V>())));
+    COMPARE(sfinae_is_callable<schar (&)(int)>(call_generator<V>()),
+	    std::is_signed<T>::value);
+    COMPARE(sfinae_is_callable<uchar (&)(int)>(call_generator<V>()),
+	    !(std::is_signed_v<T> && sizeof(T) <= sizeof(uchar)));
+    COMPARE(sfinae_is_callable<float (&)(int)>(call_generator<V>()),
+	    (std::is_floating_point<T>::value));
+
+    COMPARE(sfinae_is_callable<ullong (&)(int)>(call_generator<V>()),
+      std::__finite_max_v<T> >= std::__finite_max_v<ullong>
+      && std::__digits_v<T> >= std::__digits_v<ullong>);
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc
new file mode 100644
index 00000000000..0c8e55983a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/hypot3_fma.cc
@@ -0,0 +1,151 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+// 3-arg std::hypot needs to be fixed, this is a better reference:
+template <typename T>
+  [[gnu::optimize("-fno-unsafe-math-optimizations")]]
+  T
+  hypot3(T x, T y, T z)
+  {
+    x = std::abs(x);
+    y = std::abs(y);
+    z = std::abs(z);
+    if (std::isinf(x) || std::isinf(y) || std::isinf(z))
+      return std::__infinity_v<T>;
+    else if (std::isnan(x) || std::isnan(y) || std::isnan(z))
+      return std::__quiet_NaN_v<T>;
+    else if (x == y && y == z)
+      return x * std::sqrt(T(3));
+    else if (z == 0 && y == 0)
+      return x;
+    else if (x == 0 && z == 0)
+      return y;
+    else if (x == 0 && y == 0)
+      return z;
+    else
+      {
+	T hi = std::max(std::max(x, y), z);
+	T lo0 = std::min(std::max(x, y), z);
+	T lo1 = std::min(x, y);
+	int e = 0;
+	hi = std::frexp(hi, &e);
+	lo0 = std::ldexp(lo0, -e);
+	lo1 = std::ldexp(lo1, -e);
+	T lo = lo0 * lo0 + lo1 * lo1;
+	return std::ldexp(std::sqrt(hi * hi + lo), e);
+      }
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(1);
+    vir::test::setFuzzyness<long double>(2); // because of the bad reference
+
+    using T = typename V::value_type;
+    test_values_3arg<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>,
+	std::__infinity_v<T>,
+	-std::__infinity_v<T>,
+	std::__norm_min_v<T> / 3,
+	-0.,
+	std::__denorm_min_v<T>,
+#endif
+	0.,
+	1.,
+	-1.,
+	std::__norm_min_v<T>,
+	-std::__norm_min_v<T>,
+	2.,
+	-2.,
+	std::__finite_max_v<T> / 5,
+	std::__finite_max_v<T> / 3,
+	std::__finite_max_v<T> / 2,
+	-std::__finite_max_v<T> / 5,
+	-std::__finite_max_v<T> / 3,
+	-std::__finite_max_v<T> / 2,
+#ifdef __FAST_MATH__
+	// fast-math hypot is imprecise for the max exponent
+      },
+      {100000, std::__finite_max_v<T> / 2},
+#else
+	std::__finite_max_v<T>, -std::__finite_max_v<T>},
+      {100000},
+#endif
+      MAKE_TESTER_2(hypot, hypot3));
+#if !__FINITE_MATH_ONLY__
+    COMPARE(hypot(V(std::__finite_max_v<T>), V(std::__finite_max_v<T>), V()),
+	    V(std::__infinity_v<T>));
+    COMPARE(hypot(V(std::__finite_max_v<T>), V(), V(std::__finite_max_v<T>)),
+	    V(std::__infinity_v<T>));
+    COMPARE(hypot(V(), V(std::__finite_max_v<T>), V(std::__finite_max_v<T>)),
+	    V(std::__infinity_v<T>));
+#endif
+    COMPARE(hypot(V(std::__norm_min_v<T>), V(std::__norm_min_v<T>),
+		  V(std::__norm_min_v<T>)),
+	    V(std::__norm_min_v<T> * std::sqrt(T(3))));
+    auto&& hypot3_test
+      = [](auto a, auto b, auto c) -> decltype(hypot(a, b, c)) { return {}; };
+    VERIFY((sfinae_is_callable<V, V, V>(hypot3_test)));
+    VERIFY((sfinae_is_callable<T, T, V>(hypot3_test)));
+    VERIFY((sfinae_is_callable<V, T, T>(hypot3_test)));
+    VERIFY((sfinae_is_callable<T, V, T>(hypot3_test)));
+    VERIFY((sfinae_is_callable<T, V, V>(hypot3_test)));
+    VERIFY((sfinae_is_callable<V, T, V>(hypot3_test)));
+    VERIFY((sfinae_is_callable<V, V, T>(hypot3_test)));
+    VERIFY((sfinae_is_callable<int, int, V>(hypot3_test)));
+    VERIFY((sfinae_is_callable<int, V, int>(hypot3_test)));
+    VERIFY((sfinae_is_callable<V, T, int>(hypot3_test)));
+    VERIFY(!(sfinae_is_callable<bool, V, V>(hypot3_test)));
+    VERIFY(!(sfinae_is_callable<V, bool, V>(hypot3_test)));
+    VERIFY(!(sfinae_is_callable<V, V, bool>(hypot3_test)));
+
+    vir::test::setFuzzyness<float>(0);
+    vir::test::setFuzzyness<double>(0);
+    test_values_3arg<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+	std::__norm_min_v<T> / 3, std::__denorm_min_v<T>,
+#endif
+	0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+      {10000, -std::__finite_max_v<T> / 2, std::__finite_max_v<T> / 2},
+      MAKE_TESTER(fma));
+    auto&& fma_test
+      = [](auto a, auto b, auto c) -> decltype(fma(a, b, c)) { return {}; };
+    VERIFY((sfinae_is_callable<V, V, V>(fma_test)));
+    VERIFY((sfinae_is_callable<T, T, V>(fma_test)));
+    VERIFY((sfinae_is_callable<V, T, T>(fma_test)));
+    VERIFY((sfinae_is_callable<T, V, T>(fma_test)));
+    VERIFY((sfinae_is_callable<T, V, V>(fma_test)));
+    VERIFY((sfinae_is_callable<V, T, V>(fma_test)));
+    VERIFY((sfinae_is_callable<V, V, T>(fma_test)));
+    VERIFY((sfinae_is_callable<int, int, V>(fma_test)));
+    VERIFY((sfinae_is_callable<int, V, int>(fma_test)));
+    VERIFY((sfinae_is_callable<V, T, int>(fma_test)));
+    VERIFY((!sfinae_is_callable<V, T, bool>(fma_test)));
+    VERIFY((!sfinae_is_callable<bool, V, V>(fma_test)));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc
new file mode 100644
index 00000000000..975e69a9e35
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/integer_operators.cc
@@ -0,0 +1,218 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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..6d994572bf8
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/ldexp_scalbn_scalbln_modf.cc
@@ -0,0 +1,169 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(0);
+    vir::test::setFuzzyness<double>(0);
+
+    using T = typename V::value_type;
+
+    // See https://sourceware.org/bugzilla/show_bug.cgi?id=18031
+    const bool modf_is_broken = [] {
+      volatile T x = T(5e20) / 7;
+      T tmp;
+      return std::fabs(std::modf(x, &tmp)) >= 1;
+    }();
+    if (modf_is_broken)
+      __builtin_fprintf(stderr,
+			"NOTE: Skipping modf because std::modf is broken.\n");
+
+    test_values<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>,
+	std::__infinity_v<T>,
+	-std::__infinity_v<T>,
+	-0.,
+	std::__denorm_min_v<T>,
+	std::__norm_min_v<T> / 3,
+	-std::__denorm_min_v<T>,
+	-std::__norm_min_v<T> / 3,
+#endif
+	+0.,
+	+1.3,
+	-1.3,
+	2.1,
+	-2.1,
+	0.99,
+	0.9,
+	-0.9,
+	-0.99,
+	std::__norm_min_v<T>,
+	std::__finite_max_v<T>,
+	-std::__norm_min_v<T>,
+	-std::__finite_max_v<T>},
+      {10000},
+      [](const V input) {
+	for (int exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000})
+	  {
+	    const auto totest = ldexp(input, exp);
+	    using R = std::remove_const_t<decltype(totest)>;
+	    auto&& expected = [&](const auto& v) -> const R {
+	      R tmp = {};
+	      using std::ldexp;
+	      for (std::size_t i = 0; i < R::size(); ++i)
+		{
+		  tmp[i] = ldexp(v[i], exp);
+		}
+	      return tmp;
+	    };
+	    const R expect1 = expected(input);
+	    COMPARE(isnan(totest), isnan(expect1))
+	      << "ldexp(" << input << ", " << exp << ") = " << totest
+	      << " != " << expect1;
+	    FUZZY_COMPARE(ldexp(iif(isnan(expect1), 0, input), exp),
+			  expected(iif(isnan(expect1), 0, input)))
+	      << "\nclean = " << iif(isnan(expect1), 0, input);
+	  }
+      },
+      [](const V input) {
+	for (int exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000})
+	  {
+	    const auto totest = scalbn(input, exp);
+	    using R = std::remove_const_t<decltype(totest)>;
+	    auto&& expected = [&](const auto& v) -> const R {
+	      R tmp = {};
+	      using std::scalbn;
+	      for (std::size_t i = 0; i < R::size(); ++i)
+		{
+		  tmp[i] = scalbn(v[i], exp);
+		}
+	      return tmp;
+	    };
+	    const R expect1 = expected(input);
+	    COMPARE(isnan(totest), isnan(expect1))
+	      << "scalbn(" << input << ", " << exp << ") = " << totest
+	      << " != " << expect1;
+	    FUZZY_COMPARE(scalbn(iif(isnan(expect1), 0, input), exp),
+			  expected(iif(isnan(expect1), 0, input)))
+	      << "\nclean = " << iif(isnan(expect1), 0, input);
+	  }
+      },
+      [](const V input) {
+	for (long exp : {-10000, -100, -10, -1, 0, 1, 10, 100, 10000})
+	  {
+	    const auto totest = scalbln(input, exp);
+	    using R = std::remove_const_t<decltype(totest)>;
+	    auto&& expected = [&](const auto& v) -> const R {
+	      R tmp = {};
+	      using std::scalbln;
+	      for (std::size_t i = 0; i < R::size(); ++i)
+		{
+		  tmp[i] = scalbln(v[i], exp);
+		}
+	      return tmp;
+	    };
+	    const R expect1 = expected(input);
+	    COMPARE(isnan(totest), isnan(expect1))
+	      << "scalbln(" << input << ", " << exp << ") = " << totest
+	      << " != " << expect1;
+	    FUZZY_COMPARE(scalbln(iif(isnan(expect1), 0, input), exp),
+			  expected(iif(isnan(expect1), 0, input)))
+	      << "\nclean = " << iif(isnan(expect1), 0, input);
+	  }
+      },
+      [modf_is_broken](const V input) {
+	if (modf_is_broken)
+	  return;
+	V integral = {};
+	const V totest = modf(input, &integral);
+	auto&& expected = [&](const auto& v) -> std::pair<const V, const V> {
+	  std::pair<V, V> tmp = {};
+	  using std::modf;
+	  for (std::size_t i = 0; i < V::size(); ++i)
+	    {
+	      typename V::value_type tmp2;
+	      tmp.first[i] = modf(v[i], &tmp2);
+	      tmp.second[i] = tmp2;
+	    }
+	  return tmp;
+	};
+	const auto expect1 = expected(input);
+#ifdef __STDC_IEC_559__
+	COMPARE(isnan(totest), isnan(expect1.first))
+	  << "modf(" << input << ", iptr) = " << totest << " != " << expect1;
+	COMPARE(isnan(integral), isnan(expect1.second))
+	  << "modf(" << input << ", iptr) = " << totest << " != " << expect1;
+	COMPARE(isnan(totest), isnan(integral))
+	  << "modf(" << input << ", iptr) = " << totest << " != " << expect1;
+	const V clean = iif(isnan(totest), V(), input);
+#else
+	const V clean = iif(isnormal(input), input, V());
+#endif
+	const auto expect2 = expected(clean);
+	COMPARE(modf(clean, &integral), expect2.first) << "\nclean = " << clean;
+	COMPARE(integral, expect2.second);
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc
new file mode 100644
index 00000000000..994227c7d5a
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc
@@ -0,0 +1,229 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/conversions.h"
+
+template <typename V, typename U>
+  void
+  load_store()
+  {
+    // types, tags, and constants
+    using T = typename V::value_type;
+    auto&& gen = make_vec<V>;
+    using std::experimental::element_aligned;
+    using std::experimental::vector_aligned;
+
+    // stride_alignment: consider V::size() == 6. The only reliable alignment is
+    // 2 * sizeof(U). I.e. if the first address is aligned to 8 * sizeof(U),
+    // then the next address is 6 * sizeof(U) larger, thus only aligned to 2 *
+    // sizeof(U).
+    // => the LSB determines the stride alignment
+    constexpr size_t stride_alignment = size_t(1) << __builtin_ctz(V::size());
+    using stride_aligned_t = std::conditional_t<
+      V::size() == stride_alignment, decltype(vector_aligned),
+      std::experimental::overaligned_tag<stride_alignment * sizeof(U)>>;
+    constexpr stride_aligned_t stride_aligned = {};
+    constexpr size_t alignment
+      = 2 * std::experimental::memory_alignment_v<V, U>;
+    constexpr auto overaligned = std::experimental::overaligned<alignment>;
+    const V indexes_from_0([](auto i) { return i; });
+    for (std::size_t i = 0; i < V::size(); ++i)
+      {
+	COMPARE(indexes_from_0[i], T(i));
+      }
+
+    // loads
+    cvt_inputs<T, U> test_values;
+
+    constexpr auto mem_size
+      = test_values.size() > 3 * V::size() ? test_values.size() : 3 * V::size();
+    alignas(std::experimental::memory_alignment_v<V, U> * 2) U mem[mem_size]
+      = {};
+    alignas(std::experimental::memory_alignment_v<V, T> * 2)
+      T reference[mem_size]
+      = {};
+    for (std::size_t i = 0; i < test_values.size(); ++i)
+      {
+	const U value = test_values[i];
+	mem[i] = value;
+	reference[i] = static_cast<T>(value);
+      }
+    for (std::size_t i = test_values.size(); i < mem_size; ++i)
+      {
+	mem[i] = U(i);
+	reference[i] = mem[i];
+      }
+
+    V x(&mem[V::size()], stride_aligned);
+    auto&& compare = [&](const std::size_t offset) {
+      static int n = 0;
+      const V ref(&reference[offset], element_aligned);
+      for (auto i = 0ul; i < V::size(); ++i)
+	{
+	  if (is_conversion_undefined<T>(mem[i + offset]))
+	    {
+	      continue;
+	    }
+	  COMPARE(x[i], reference[i + offset])
+	    << "\nbefore conversion: " << mem[i + offset]
+	    << "\n   offset = " << offset << "\n        x = " << x
+	    << "\nreference = " << ref << "\nx == ref  = " << (x == ref)
+	    << "\ncall no. " << n;
+	}
+      ++n;
+    };
+    compare(V::size());
+    x = V{mem, overaligned};
+    compare(0);
+    x = {&mem[1], element_aligned};
+    compare(1);
+
+    x.copy_from(&mem[V::size()], stride_aligned);
+    compare(V::size());
+    x.copy_from(&mem[1], element_aligned);
+    compare(1);
+    x.copy_from(mem, vector_aligned);
+    compare(0);
+
+    for (std::size_t i = 0; i < mem_size - V::size(); ++i)
+      {
+	x.copy_from(&mem[i], element_aligned);
+	compare(i);
+      }
+
+    for (std::size_t i = 0; i < test_values.size(); ++i)
+      {
+	mem[i] = U(i);
+      }
+    x = indexes_from_0;
+    using M = typename V::mask_type;
+    const M alternating_mask = make_mask<M>({0, 1});
+    where(alternating_mask, x).copy_from(&mem[V::size()], stride_aligned);
+
+    const V indexes_from_size = gen({T(V::size())}, 1);
+    COMPARE(x == indexes_from_size, alternating_mask)
+      << "x: " << x << "\nindexes_from_size: " << indexes_from_size;
+    COMPARE(x == indexes_from_0, !alternating_mask);
+    where(alternating_mask, x).copy_from(&mem[1], element_aligned);
+
+    const V indexes_from_1 = gen({1, 2, 3, 4}, 4);
+    COMPARE(x == indexes_from_1, alternating_mask);
+    COMPARE(x == indexes_from_0, !alternating_mask);
+    where(!alternating_mask, x).copy_from(mem, overaligned);
+    COMPARE(x == indexes_from_0, !alternating_mask);
+    COMPARE(x == indexes_from_1, alternating_mask);
+
+    x = where(alternating_mask, V()).copy_from(&mem[V::size()], stride_aligned);
+    COMPARE(x == indexes_from_size, alternating_mask);
+    COMPARE(x == 0, !alternating_mask);
+
+    x = where(!alternating_mask, V()).copy_from(&mem[1], element_aligned);
+    COMPARE(x == indexes_from_1, !alternating_mask);
+    COMPARE(x == 0, alternating_mask);
+
+    // stores
+    auto&& init_mem = [&mem](U init) {
+      for (auto i = mem_size; i; --i)
+	{
+	  mem[i - 1] = init;
+	}
+    };
+    init_mem(-1);
+    x = indexes_from_1;
+    x.copy_to(&mem[V::size()], stride_aligned);
+    std::size_t i = 0;
+    for (; i < V::size(); ++i)
+      {
+	COMPARE(mem[i], U(-1)) << "i: " << i;
+      }
+    for (; i < 2 * V::size(); ++i)
+      {
+	COMPARE(mem[i], U(i - V::size() + 1)) << "i: " << i;
+      }
+    for (; i < 3 * V::size(); ++i)
+      {
+	COMPARE(mem[i], U(-1)) << "i: " << i;
+      }
+
+    init_mem(-1);
+    x.copy_to(&mem[1], element_aligned);
+    COMPARE(mem[0], U(-1));
+    for (i = 1; i <= V::size(); ++i)
+      {
+	COMPARE(mem[i], U(i));
+      }
+    for (; i < 3 * V::size(); ++i)
+      {
+	COMPARE(mem[i], U(-1));
+      }
+
+    init_mem(-1);
+    x.copy_to(mem, vector_aligned);
+    for (i = 0; i < V::size(); ++i)
+      {
+	COMPARE(mem[i], U(i + 1));
+      }
+    for (; i < 3 * V::size(); ++i)
+      {
+	COMPARE(mem[i], U(-1));
+      }
+
+    init_mem(-1);
+    where(alternating_mask, indexes_from_0)
+      .copy_to(&mem[V::size()], stride_aligned);
+    for (i = 0; i < V::size() + 1; ++i)
+      {
+	COMPARE(mem[i], U(-1));
+      }
+    for (; i < 2 * V::size(); i += 2)
+      {
+	COMPARE(mem[i], U(i - V::size()));
+      }
+    for (i = V::size() + 2; i < 2 * V::size(); i += 2)
+      {
+	COMPARE(mem[i], U(-1));
+      }
+    for (; i < 3 * V::size(); ++i)
+      {
+	COMPARE(mem[i], U(-1));
+      }
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    load_store<V, long double>();
+    load_store<V, double>();
+    load_store<V, float>();
+    load_store<V, long long>();
+    load_store<V, unsigned long long>();
+    load_store<V, unsigned long>();
+    load_store<V, long>();
+    load_store<V, int>();
+    load_store<V, unsigned int>();
+    load_store<V, short>();
+    load_store<V, unsigned short>();
+    load_store<V, char>();
+    load_store<V, signed char>();
+    load_store<V, unsigned char>();
+    load_store<V, char32_t>();
+    load_store<V, char16_t>();
+    load_store<V, wchar_t>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc
new file mode 100644
index 00000000000..29c686db697
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/logarithm.cc
@@ -0,0 +1,83 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(1);
+
+    using T = typename V::value_type;
+    constexpr T nan = std::__quiet_NaN_v<T>;
+    constexpr T inf = std::__infinity_v<T>;
+    constexpr T denorm_min = std::__denorm_min_v<T>;
+    constexpr T norm_min = std::__norm_min_v<T>;
+    constexpr T min = std::__finite_min_v<T>;
+    constexpr T max = std::__finite_max_v<T>;
+    test_values<V>({1,
+		    2,
+		    4,
+		    8,
+		    16,
+		    32,
+		    64,
+		    128,
+		    256,
+		    512,
+		    1024,
+		    2048,
+		    3,
+		    5,
+		    7,
+		    15,
+		    17,
+		    31,
+		    33,
+		    63,
+		    65,
+#ifdef __STDC_IEC_559__
+		    nan,
+		    inf,
+		    -inf,
+		    denorm_min,
+		    -denorm_min,
+		    norm_min / 3,
+		    -norm_min / 3,
+		    -T(),
+		    -norm_min,
+		    min,
+		    T(),
+#endif
+		    norm_min,
+		    max},
+		   {10000,
+#ifdef __STDC_IEC_559__
+		    min / 2,
+#else
+		    norm_min,
+#endif
+		    max / 2},
+		   MAKE_TESTER(log), MAKE_TESTER(log10), MAKE_TESTER(log1p),
+		   MAKE_TESTER(log2), MAKE_TESTER(logb));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc
new file mode 100644
index 00000000000..7fc8201caf6
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_broadcast.cc
@@ -0,0 +1,67 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    static_assert(std::is_convertible<typename M::reference, bool>::value,
+		  "A smart_reference<simd_mask> must be convertible to bool.");
+    static_assert(
+      std::is_same<bool, decltype(std::declval<const typename M::reference&>()
+				  == true)>::value,
+      "A smart_reference<simd_mask> must be comparable against bool.");
+    static_assert(
+      vir::test::sfinae_is_callable<typename M::reference&&, bool>(
+	[](auto&& a, auto&& b) -> decltype(std::declval<decltype(a)>()
+					   == std::declval<decltype(b)>()) {
+	  return {};
+	}),
+      "A smart_reference<simd_mask> must be comparable against bool.");
+    VERIFY(std::experimental::is_simd_mask_v<M>);
+
+    {
+      M x;     // uninitialized
+      x = M{}; // default broadcasts 0
+      COMPARE(x, M(false));
+      COMPARE(x, M());
+      COMPARE(x, M{});
+      x = M(); // default broadcasts 0
+      COMPARE(x, M(false));
+      COMPARE(x, M());
+      COMPARE(x, M{});
+      x = x;
+      for (std::size_t i = 0; i < M::size(); ++i)
+	{
+	  COMPARE(x[i], false);
+	}
+    }
+
+    M x(true);
+    M y(false);
+    for (std::size_t i = 0; i < M::size(); ++i)
+      {
+	COMPARE(x[i], true);
+	COMPARE(y[i], false);
+      }
+    y = M(true);
+    COMPARE(x, y);
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc
new file mode 100644
index 00000000000..8cec912250a
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_conversions.cc
@@ -0,0 +1,113 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+namespace stdx = std::experimental;
+
+template <typename From, typename To>
+  void
+  conversions()
+  {
+    using ToV = typename To::simd_type;
+
+    using stdx::simd_cast;
+    using stdx::static_simd_cast;
+    using stdx::__proposed::resizing_simd_cast;
+
+    auto x = resizing_simd_cast<To>(From());
+    COMPARE(typeid(x), typeid(To));
+    COMPARE(x, To());
+
+    x = resizing_simd_cast<To>(From(true));
+    const To ref = ToV([](auto i) { return i; }) < int(From::size());
+    COMPARE(x, ref) << "converted from: " << From(true);
+
+    const ullong all_bits = ~ullong() >> (64 - From::size());
+    for (ullong bit_pos = 1; bit_pos /*until overflow*/; bit_pos *= 2)
+      {
+	for (ullong bits : {bit_pos & all_bits, ~bit_pos & all_bits})
+	  {
+	    const auto from = From::__from_bitset(bits);
+	    const auto to = resizing_simd_cast<To>(from);
+	    COMPARE(to, To::__from_bitset(bits))
+	      << "\nfrom: " << from << "\nbits: " << std::hex << bits << std::dec;
+	    for (std::size_t i = 0; i < To::size(); ++i)
+	      {
+		COMPARE(to[i], (bits >> i) & 1)
+		  << "\nfrom: " << from << "\nto: " << to
+		  << "\nbits: " << std::hex << bits << std::dec << "\ni: " << i;
+	      }
+	  }
+      }
+  }
+
+template <typename T, typename V, typename = void>
+  struct rebind_or_max_fixed
+  {
+    using type = stdx::rebind_simd_t<
+      T, stdx::resize_simd_t<stdx::simd_abi::max_fixed_size<T>, V>>;
+  };
+
+template <typename T, typename V>
+  struct rebind_or_max_fixed<T, V, std::void_t<stdx::rebind_simd_t<T, V>>>
+  {
+    using type = stdx::rebind_simd_t<T, V>;
+  };
+
+template <typename From, typename To>
+  void
+  apply_abis()
+  {
+    using M0 = typename rebind_or_max_fixed<To, From>::type;
+    using M1 = stdx::native_simd_mask<To>;
+    using M2 = stdx::simd_mask<To>;
+    using M3 = stdx::simd_mask<To, stdx::simd_abi::scalar>;
+
+    using std::is_same_v;
+    conversions<From, M0>();
+    if constexpr (!is_same_v<M1, M0>)
+      conversions<From, M1>();
+    if constexpr (!is_same_v<M2, M0> && !is_same_v<M2, M1>)
+      conversions<From, M2>();
+    if constexpr (!is_same_v<M3, M0> && !is_same_v<M3, M1> && !is_same_v<M3, M2>)
+      conversions<From, M3>();
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    apply_abis<M, ldouble>();
+    apply_abis<M, double>();
+    apply_abis<M, float>();
+    apply_abis<M, ullong>();
+    apply_abis<M, llong>();
+    apply_abis<M, ulong>();
+    apply_abis<M, long>();
+    apply_abis<M, uint>();
+    apply_abis<M, int>();
+    apply_abis<M, ushort>();
+    apply_abis<M, short>();
+    apply_abis<M, uchar>();
+    apply_abis<M, schar>();
+    apply_abis<M, char>();
+    apply_abis<M, wchar_t>();
+    apply_abis<M, char16_t>();
+    apply_abis<M, char32_t>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc
new file mode 100644
index 00000000000..e1760e3f37f
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_implicit_cvt.cc
@@ -0,0 +1,102 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <class M, class M2>
+  constexpr bool assign_should_work
+    = std::is_same<M, M2>::value
+	|| (std::is_same<typename M::abi_type,
+			 std::experimental::simd_abi::fixed_size<M::size()>>::value
+	      && std::is_same<typename M::abi_type, typename M2::abi_type>::value);
+
+template <class M, class M2>
+  constexpr bool assign_should_not_work = !assign_should_work<M, M2>;
+
+template <class L, class R>
+  std::enable_if_t<assign_should_work<L, R>>
+  implicit_conversions_test()
+  {
+    L x = R(true);
+    COMPARE(x, L(true));
+    x = R(false);
+    COMPARE(x, L(false));
+    R y(false);
+    y[0] = true;
+    x = y;
+    L ref(false);
+    ref[0] = true;
+    COMPARE(x, ref);
+  }
+
+template <class L, class R>
+  std::enable_if_t<assign_should_not_work<L, R>>
+  implicit_conversions_test()
+  {
+    VERIFY((is_substitution_failure<L&, R, assignment>) );
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    using std::experimental::fixed_size_simd_mask;
+    using std::experimental::native_simd_mask;
+    using std::experimental::simd_mask;
+
+    implicit_conversions_test<M, simd_mask<ldouble>>();
+    implicit_conversions_test<M, simd_mask<double>>();
+    implicit_conversions_test<M, simd_mask<float>>();
+    implicit_conversions_test<M, simd_mask<ullong>>();
+    implicit_conversions_test<M, simd_mask<llong>>();
+    implicit_conversions_test<M, simd_mask<ulong>>();
+    implicit_conversions_test<M, simd_mask<long>>();
+    implicit_conversions_test<M, simd_mask<uint>>();
+    implicit_conversions_test<M, simd_mask<int>>();
+    implicit_conversions_test<M, simd_mask<ushort>>();
+    implicit_conversions_test<M, simd_mask<short>>();
+    implicit_conversions_test<M, simd_mask<uchar>>();
+    implicit_conversions_test<M, simd_mask<schar>>();
+    implicit_conversions_test<M, native_simd_mask<ldouble>>();
+    implicit_conversions_test<M, native_simd_mask<double>>();
+    implicit_conversions_test<M, native_simd_mask<float>>();
+    implicit_conversions_test<M, native_simd_mask<ullong>>();
+    implicit_conversions_test<M, native_simd_mask<llong>>();
+    implicit_conversions_test<M, native_simd_mask<ulong>>();
+    implicit_conversions_test<M, native_simd_mask<long>>();
+    implicit_conversions_test<M, native_simd_mask<uint>>();
+    implicit_conversions_test<M, native_simd_mask<int>>();
+    implicit_conversions_test<M, native_simd_mask<ushort>>();
+    implicit_conversions_test<M, native_simd_mask<short>>();
+    implicit_conversions_test<M, native_simd_mask<uchar>>();
+    implicit_conversions_test<M, native_simd_mask<schar>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<ldouble, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<double, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<float, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<ullong, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<llong, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<ulong, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<long, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<uint, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<int, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<ushort, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<short, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<uchar, M::size()>>();
+    implicit_conversions_test<M, fixed_size_simd_mask<schar, M::size()>>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc
new file mode 100644
index 00000000000..0f43428b7c6
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_loadstore.cc
@@ -0,0 +1,161 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+// simd_mask generator functions
+template <class M>
+  M
+  make_mask(const std::initializer_list<bool>& init)
+  {
+    std::size_t i = 0;
+    M r = {};
+    for (;;)
+      {
+	for (bool x : init)
+	  {
+	    r[i] = x;
+	    if (++i == M::size())
+	      {
+		return r;
+	      }
+	  }
+      }
+  }
+
+template <class M>
+  M
+  make_alternating_mask()
+  {
+    return make_mask<M>({false, true});
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    // loads
+    constexpr size_t alignment = 2 * std::experimental::memory_alignment_v<M>;
+    alignas(alignment) bool mem[3 * M::size()];
+    std::memset(mem, 0, sizeof(mem));
+    for (std::size_t i = 1; i < sizeof(mem) / sizeof(*mem); i += 2)
+      {
+	COMPARE(mem[i - 1], false);
+	mem[i] = true;
+      }
+    using std::experimental::element_aligned;
+    using std::experimental::vector_aligned;
+    constexpr size_t stride_alignment
+      = M::size() & 1
+	  ? 1
+	  : M::size() & 2
+	  ? 2
+	  : M::size() & 4
+	  ? 4
+	  : M::size() & 8
+	  ? 8
+	  : M::size() & 16
+	  ? 16
+	  : M::size() & 32
+	  ? 32
+	  : M::size() & 64
+	  ? 64
+	  : M::size() & 128 ? 128
+			    : M::size() & 256 ? 256 : 512;
+    using stride_aligned_t = std::conditional_t<
+      M::size() == stride_alignment, decltype(vector_aligned),
+      std::experimental::overaligned_tag<stride_alignment * sizeof(bool)>>;
+    constexpr stride_aligned_t stride_aligned = {};
+    constexpr auto overaligned = std::experimental::overaligned<alignment>;
+
+    const M alternating_mask = make_alternating_mask<M>();
+
+    M x(&mem[M::size()], stride_aligned);
+    COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : alternating_mask)
+      << x.__to_bitset()
+      << ", alternating_mask: " << alternating_mask.__to_bitset();
+    x = {&mem[1], element_aligned};
+    COMPARE(x, !alternating_mask);
+    x = M{mem, overaligned};
+    COMPARE(x, alternating_mask);
+
+    x.copy_from(&mem[M::size()], stride_aligned);
+    COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : alternating_mask);
+    x.copy_from(&mem[1], element_aligned);
+    COMPARE(x, !alternating_mask);
+    x.copy_from(mem, vector_aligned);
+    COMPARE(x, alternating_mask);
+
+    x = !alternating_mask;
+    where(alternating_mask, x).copy_from(&mem[M::size()], stride_aligned);
+    COMPARE(x, M::size() % 2 == 1 ? !alternating_mask : M{true});
+    x = M(true);                                                    // 1111
+    where(alternating_mask, x).copy_from(&mem[1], element_aligned); // load .0.0
+    COMPARE(x, !alternating_mask);                                  // 1010
+    where(alternating_mask, x).copy_from(mem, overaligned);         // load .1.1
+    COMPARE(x, M{true});                                            // 1111
+
+    // stores
+    memset(mem, 0, sizeof(mem));
+    x = M(true);
+    x.copy_to(&mem[M::size()], stride_aligned);
+    std::size_t i = 0;
+    for (; i < M::size(); ++i)
+      {
+	COMPARE(mem[i], false);
+      }
+    for (; i < 2 * M::size(); ++i)
+      {
+	COMPARE(mem[i], true) << "i: " << i << ", x: " << x;
+      }
+    for (; i < 3 * M::size(); ++i)
+      {
+	COMPARE(mem[i], false);
+      }
+    memset(mem, 0, sizeof(mem));
+    x.copy_to(&mem[1], element_aligned);
+    COMPARE(mem[0], false);
+    for (i = 1; i <= M::size(); ++i)
+      {
+	COMPARE(mem[i], true);
+      }
+    for (; i < 3 * M::size(); ++i)
+      {
+	COMPARE(mem[i], false);
+      }
+    memset(mem, 0, sizeof(mem));
+    alternating_mask.copy_to(mem, overaligned);
+    for (i = 0; i < M::size(); ++i)
+      {
+	COMPARE(mem[i], (i & 1) == 1);
+      }
+    for (; i < 3 * M::size(); ++i)
+      {
+	COMPARE(mem[i], false);
+      }
+    x.copy_to(mem, vector_aligned);
+    where(alternating_mask, !x).copy_to(mem, overaligned);
+    for (i = 0; i < M::size(); ++i)
+      {
+	COMPARE(mem[i], i % 2 == 0);
+      }
+    for (; i < 3 * M::size(); ++i)
+      {
+	COMPARE(mem[i], false);
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc
new file mode 100644
index 00000000000..738b97c3dca
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operator_cvt.cc
@@ -0,0 +1,111 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+using schar = signed char;
+using uchar = unsigned char;
+using ushort = unsigned short;
+using uint = unsigned int;
+using ulong = unsigned long;
+using llong = long long;
+using ullong = unsigned long long;
+using ldouble = long double;
+using wchar = wchar_t;
+using char16 = char16_t;
+using char32 = char32_t;
+
+template <typename M0, typename M1>
+  constexpr bool
+  bit_and_is_illformed()
+  {
+    return is_substitution_failure<M0, M1, std::bit_and<>>;
+  }
+
+template <typename M0, typename M1>
+  void
+  test_binary_op_cvt()
+  {
+    COMPARE((bit_and_is_illformed<M0, M1>()), !(std::is_same_v<M0, M1>) );
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    // binary ops without conversions work
+    COMPARE(typeid(M() & M()), typeid(M));
+
+    // nothing else works: no implicit conv. or ambiguous
+    using std::experimental::fixed_size_simd_mask;
+    using std::experimental::native_simd_mask;
+    using std::experimental::simd_mask;
+    test_binary_op_cvt<M, bool>();
+
+    test_binary_op_cvt<M, simd_mask<ldouble>>();
+    test_binary_op_cvt<M, simd_mask<double>>();
+    test_binary_op_cvt<M, simd_mask<float>>();
+    test_binary_op_cvt<M, simd_mask<ullong>>();
+    test_binary_op_cvt<M, simd_mask<llong>>();
+    test_binary_op_cvt<M, simd_mask<ulong>>();
+    test_binary_op_cvt<M, simd_mask<long>>();
+    test_binary_op_cvt<M, simd_mask<uint>>();
+    test_binary_op_cvt<M, simd_mask<int>>();
+    test_binary_op_cvt<M, simd_mask<ushort>>();
+    test_binary_op_cvt<M, simd_mask<short>>();
+    test_binary_op_cvt<M, simd_mask<uchar>>();
+    test_binary_op_cvt<M, simd_mask<schar>>();
+    test_binary_op_cvt<M, simd_mask<wchar>>();
+    test_binary_op_cvt<M, simd_mask<char16>>();
+    test_binary_op_cvt<M, simd_mask<char32>>();
+
+    test_binary_op_cvt<M, native_simd_mask<ldouble>>();
+    test_binary_op_cvt<M, native_simd_mask<double>>();
+    test_binary_op_cvt<M, native_simd_mask<float>>();
+    test_binary_op_cvt<M, native_simd_mask<ullong>>();
+    test_binary_op_cvt<M, native_simd_mask<llong>>();
+    test_binary_op_cvt<M, native_simd_mask<ulong>>();
+    test_binary_op_cvt<M, native_simd_mask<long>>();
+    test_binary_op_cvt<M, native_simd_mask<uint>>();
+    test_binary_op_cvt<M, native_simd_mask<int>>();
+    test_binary_op_cvt<M, native_simd_mask<ushort>>();
+    test_binary_op_cvt<M, native_simd_mask<short>>();
+    test_binary_op_cvt<M, native_simd_mask<uchar>>();
+    test_binary_op_cvt<M, native_simd_mask<schar>>();
+    test_binary_op_cvt<M, native_simd_mask<wchar>>();
+    test_binary_op_cvt<M, native_simd_mask<char16>>();
+    test_binary_op_cvt<M, native_simd_mask<char32>>();
+
+    test_binary_op_cvt<M, fixed_size_simd_mask<ldouble, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<double, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<float, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<ullong, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<llong, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<ulong, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<long, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<uint, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<int, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<ushort, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<short, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<uchar, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<schar, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<wchar, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<char16, 2>>();
+    test_binary_op_cvt<M, fixed_size_simd_mask<char32, 2>>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc
new file mode 100644
index 00000000000..58255cf1e1b
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_operators.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    { // compares
+      M x(true), y(false);
+      VERIFY(all_of(x == x));
+      VERIFY(all_of(x != y));
+      VERIFY(all_of(y != x));
+      VERIFY(!all_of(x != x));
+      VERIFY(!all_of(x == y));
+      VERIFY(!all_of(y == x));
+    }
+    { // subscripting
+      M x(true);
+      for (std::size_t i = 0; i < M::size(); ++i)
+	{
+	  COMPARE(x[i], true) << "\nx: " << x << ", i: " << i;
+	  x[i] = !x[i];
+	}
+      COMPARE(x, M{false});
+      for (std::size_t i = 0; i < M::size(); ++i)
+	{
+	  COMPARE(x[i], false) << "\nx: " << x << ", i: " << i;
+	  x[i] = !x[i];
+	}
+      COMPARE(x, M{true});
+    }
+    { // negation
+      M x(false);
+      M y = !x;
+      COMPARE(y, M{true});
+      COMPARE(!y, x);
+    }
+  }
+
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc
new file mode 100644
index 00000000000..1190eaf5457
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/mask_reductions.cc
@@ -0,0 +1,226 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// simd_mask generator functions
+template <class M>
+  M
+  make_mask(const std::initializer_list<bool>& init)
+  {
+    std::size_t i = 0;
+    M r = {};
+    for (;;)
+      {
+	for (bool x : init)
+	  {
+	    r[i] = x;
+	    if (++i == M::size())
+	      {
+		return r;
+	      }
+	  }
+      }
+  }
+
+template <class M>
+  M
+  make_alternating_mask()
+  {
+    return make_mask<M>({false, true});
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    const M alternating_mask = make_alternating_mask<M>();
+    COMPARE(alternating_mask[0], false); // assumption below
+    auto&& gen = make_mask<M>;
+
+    // all_of
+    VERIFY(all_of(M{true}));
+    VERIFY(!all_of(alternating_mask));
+    VERIFY(!all_of(M{false}));
+    using std::experimental::all_of;
+    VERIFY(all_of(true));
+    VERIFY(!all_of(false));
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::all_of(x)) { return {}; }));
+
+    // any_of
+    VERIFY(any_of(M{true}));
+    COMPARE(any_of(alternating_mask), M::size() > 1);
+    VERIFY(!any_of(M{false}));
+    using std::experimental::any_of;
+    VERIFY(any_of(true));
+    VERIFY(!any_of(false));
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::any_of(x)) { return {}; }));
+
+    // none_of
+    VERIFY(!none_of(M{true}));
+    COMPARE(none_of(alternating_mask), M::size() == 1);
+    VERIFY(none_of(M{false}));
+    using std::experimental::none_of;
+    VERIFY(!none_of(true));
+    VERIFY(none_of(false));
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::none_of(x)) { return {}; }));
+
+    // some_of
+    VERIFY(!some_of(M{true}));
+    VERIFY(!some_of(M{false}));
+    if (M::size() > 1)
+      {
+	VERIFY(some_of(gen({true, false})));
+	VERIFY(some_of(gen({false, true})));
+	if (M::size() > 3)
+	  {
+	    VERIFY(some_of(gen({0, 0, 0, 1})));
+	  }
+      }
+    using std::experimental::some_of;
+    VERIFY(!some_of(true));
+    VERIFY(!some_of(false));
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::some_of(x)) { return {}; }));
+
+    // popcount
+    COMPARE(popcount(M{true}), int(M::size()));
+    COMPARE(popcount(alternating_mask), int(M::size()) / 2);
+    COMPARE(popcount(M{false}), 0);
+    COMPARE(popcount(gen({0, 0, 1})), int(M::size()) / 3);
+    COMPARE(popcount(gen({0, 0, 0, 1})), int(M::size()) / 4);
+    COMPARE(popcount(gen({0, 0, 0, 0, 1})), int(M::size()) / 5);
+    COMPARE(std::experimental::popcount(true), 1);
+    COMPARE(std::experimental::popcount(false), 0);
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::popcount(x)) { return {}; }));
+
+    // find_first_set
+    {
+      M x(false);
+      for (int i = int(M::size() / 2 - 1); i >= 0; --i)
+	{
+	  x[i] = true;
+	  COMPARE(find_first_set(x), i) << x;
+	}
+      x = M(false);
+      for (int i = int(M::size() - 1); i >= 0; --i)
+	{
+	  x[i] = true;
+	  COMPARE(find_first_set(x), i) << x;
+	}
+    }
+    COMPARE(find_first_set(M{true}), 0);
+    if (M::size() > 1)
+      {
+	COMPARE(find_first_set(gen({0, 1})), 1);
+      }
+    if (M::size() > 2)
+      {
+	COMPARE(find_first_set(gen({0, 0, 1})), 2);
+      }
+    COMPARE(std::experimental::find_first_set(true), 0);
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::find_first_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::find_first_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::find_first_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::find_first_set(x)) {
+	  return {};
+	}));
+
+    // find_last_set
+    {
+      M x(false);
+      for (int i = 0; i < int(M::size()); ++i)
+	{
+	  x[i] = true;
+	  COMPARE(find_last_set(x), i) << x;
+	}
+    }
+    COMPARE(find_last_set(M{true}), int(M::size()) - 1);
+    if (M::size() > 1)
+      {
+	COMPARE(find_last_set(gen({1, 0})),
+		int(M::size()) - 2 + int(M::size() & 1));
+      }
+    if (M::size() > 3 && (M::size() & 3) == 0)
+      {
+	COMPARE(find_last_set(gen({1, 0, 0, 0})),
+		int(M::size()) - 4 - int(M::size() & 3));
+      }
+    COMPARE(std::experimental::find_last_set(true), 0);
+    VERIFY(sfinae_is_callable<bool>(
+	[](auto x) -> decltype(std::experimental::find_last_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<int>(
+	[](auto x) -> decltype(std::experimental::find_last_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<float>(
+	[](auto x) -> decltype(std::experimental::find_last_set(x)) {
+	  return {};
+	}));
+    VERIFY(!sfinae_is_callable<char>(
+	[](auto x) -> decltype(std::experimental::find_last_set(x)) {
+	  return {};
+	}));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc
new file mode 100644
index 00000000000..bce01264f3c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_1arg.cc
@@ -0,0 +1,107 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(0);
+    vir::test::setFuzzyness<double>(0);
+
+    using T = typename V::value_type;
+    constexpr T inf = std::__infinity_v<T>;
+    constexpr T nan = std::__quiet_NaN_v<T>;
+    constexpr T denorm_min = std::__denorm_min_v<T>;
+    constexpr T norm_min = std::__norm_min_v<T>;
+    constexpr T max = std::__finite_max_v<T>;
+#if defined __LONG_DOUBLE_IBM128__
+    // On POWER with IBM128 long double, 1+eps and 2-eps is not a constant
+    // expression. Until this is fixed, just use const instead of constexpr.
+    // (error: '(1.0e+0l + 4.94065645841246544176568792868221e-324l)' is not a
+    // constant expression)
+    const T after_one = 1 + std::__epsilon_v<T>;
+    const T before_one = (2 - std::__epsilon_v<T>) / 2;
+#else
+    constexpr T after_one = 1 + std::__epsilon_v<T>;
+    constexpr T before_one = (2 - std::__epsilon_v<T>) / 2;
+#endif
+    const std::initializer_list<T>
+      input_values = {+0.,
+		      0.5,
+		      -0.5,
+		      before_one,
+		      -before_one,
+		      after_one,
+		      -after_one,
+		      1.5,
+		      -1.5,
+		      2 * before_one,
+		      -2 * before_one,
+		      2 * after_one,
+		      -2 * after_one,
+		      2.5,
+		      -2.5,
+		      0x1.fffffffffffffp52,
+		      -0x1.fffffffffffffp52,
+		      0x1.ffffffffffffep52,
+		      -0x1.ffffffffffffep52,
+		      0x1.ffffffffffffdp52,
+		      -0x1.ffffffffffffdp52,
+		      0x1.fffffep21,
+		      -0x1.fffffep21,
+		      0x1.fffffcp21,
+		      -0x1.fffffcp21,
+		      0x1.fffffep22,
+		      -0x1.fffffep22,
+		      0x1.fffffcp22,
+		      -0x1.fffffcp22,
+		      0x1.fffffep23,
+		      -0x1.fffffep23,
+		      0x1.fffffcp23,
+		      -0x1.fffffcp23,
+		      0x1.8p23,
+		      -0x1.8p23,
+		      inf,
+		      -inf,
+		      -0.,
+		      nan,
+		      denorm_min,
+		      norm_min / 3,
+		      norm_min,
+		      max};
+    test_values<V>(input_values, {10000}, MAKE_TESTER(erf), MAKE_TESTER(erfc),
+		   MAKE_TESTER(tgamma), MAKE_TESTER(lgamma), MAKE_TESTER(ceil),
+		   MAKE_TESTER(floor), MAKE_TESTER(trunc), MAKE_TESTER(round),
+		   MAKE_TESTER(lround), MAKE_TESTER(llround),
+		   MAKE_TESTER(nearbyint), MAKE_TESTER(rint), MAKE_TESTER(lrint),
+		   MAKE_TESTER(llrint), MAKE_TESTER(ilogb));
+
+    // sqrt(x) on x87 is precise in 80 bits, but the subsequent rounding can be
+    // wrong (up to 1 ULP)
+#if __FLT_EVAL_METHOD__ == 1
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(0);
+#elif __FLT_EVAL_METHOD__ == 2
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(1);
+#endif
+    test_values<V>(input_values, {10000}, MAKE_TESTER(sqrt));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc
new file mode 100644
index 00000000000..57b7b3aeb5c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/math_2arg.cc
@@ -0,0 +1,79 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(1);
+    vir::test::setFuzzyness<long double>(1);
+    test_values_2arg<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+	std::__denorm_min_v<T>, std::__norm_min_v<T> / 3,
+#endif
+	+0., std::__norm_min_v<T>, 1., 2., std::__finite_max_v<T> / 5,
+	std::__finite_max_v<T> / 3, std::__finite_max_v<T> / 2,
+#ifdef __FAST_MATH__
+	// fast-math hypot is imprecise for the max exponent
+      },
+      {100000, std::__finite_max_v<T> / 2},
+#else
+	std::__finite_max_v<T>},
+      {100000},
+#endif
+      MAKE_TESTER(hypot));
+#if !__FINITE_MATH_ONLY__
+    COMPARE(hypot(V(std::__finite_max_v<T>), V(std::__finite_max_v<T>)),
+	    V(std::__infinity_v<T>));
+#endif
+    COMPARE(hypot(V(std::__norm_min_v<T>), V(std::__norm_min_v<T>)),
+	    V(std::__norm_min_v<T> * std::sqrt(T(2))));
+    VERIFY((sfinae_is_callable<V, V>(
+	  [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+    VERIFY((sfinae_is_callable<typename V::value_type, V>(
+	  [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+    VERIFY((sfinae_is_callable<V, typename V::value_type>(
+	  [](auto a, auto b) -> decltype(hypot(a, b)) { return {}; })));
+
+    vir::test::setFuzzyness<float>(0);
+    vir::test::setFuzzyness<double>(0);
+    vir::test::setFuzzyness<long double>(0);
+    test_values_2arg<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>,
+	std::__denorm_min_v<T>, std::__norm_min_v<T> / 3, -0.,
+#endif
+	+0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+      {10000}, MAKE_TESTER(pow), MAKE_TESTER(fmod), MAKE_TESTER(remainder),
+      MAKE_TESTER_NOFPEXCEPT(copysign),
+      MAKE_TESTER(nextafter), // MAKE_TESTER(nexttoward),
+      MAKE_TESTER(fdim), MAKE_TESTER(fmax), MAKE_TESTER(fmin),
+      MAKE_TESTER_NOFPEXCEPT(isgreater), MAKE_TESTER_NOFPEXCEPT(isgreaterequal),
+      MAKE_TESTER_NOFPEXCEPT(isless), MAKE_TESTER_NOFPEXCEPT(islessequal),
+      MAKE_TESTER_NOFPEXCEPT(islessgreater), MAKE_TESTER_NOFPEXCEPT(isunordered));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc
new file mode 100644
index 00000000000..a04cd34e3d4
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/operator_cvt.cc
@@ -0,0 +1,1072 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+
+// type with sizeof(char) but different signedness
+using xchar = std::conditional_t<std::is_unsigned_v<char>, schar, uchar>;
+
+using vschar = std::experimental::native_simd<schar>;
+using vuchar = std::experimental::native_simd<uchar>;
+using vshort = std::experimental::native_simd<short>;
+using vushort = std::experimental::native_simd<ushort>;
+using vint = std::experimental::native_simd<int>;
+using vuint = std::experimental::native_simd<uint>;
+using vlong = std::experimental::native_simd<long>;
+using vulong = std::experimental::native_simd<ulong>;
+using vllong = std::experimental::native_simd<llong>;
+using vullong = std::experimental::native_simd<ullong>;
+using vfloat = std::experimental::native_simd<float>;
+using vdouble = std::experimental::native_simd<double>;
+using vldouble = std::experimental::native_simd<long double>;
+using vchar = std::experimental::native_simd<char>;
+using vxchar = std::experimental::native_simd<xchar>;
+
+template <typename T>
+  using vi8 = std::experimental::fixed_size_simd<T, vschar::size()>;
+template <typename T>
+  using vi16 = std::experimental::fixed_size_simd<T, vshort::size()>;
+template <typename T>
+  using vf32 = std::experimental::fixed_size_simd<T, vfloat::size()>;
+template <typename T>
+  using vi32 = std::experimental::fixed_size_simd<T, vint::size()>;
+template <typename T>
+  using vf64 = std::experimental::fixed_size_simd<T, vdouble::size()>;
+template <typename T>
+  using vi64 = std::experimental::fixed_size_simd<T, vllong::size()>;
+template <typename T>
+  using vl = typename std::conditional<sizeof(long) == sizeof(llong), vi64<T>,
+				       vi32<T>>::type;
+
+template <class A, class B, class Expected = A>
+  void
+  binary_op_return_type()
+  {
+    using namespace vir::test;
+    static_assert(std::is_same<A, Expected>::value, "");
+    using AC = std::add_const_t<A>;
+    using BC = std::add_const_t<B>;
+    COMPARE(typeid(A() + B()), typeid(Expected));
+    COMPARE(typeid(B() + A()), typeid(Expected));
+    COMPARE(typeid(AC() + BC()), typeid(Expected));
+    COMPARE(typeid(BC() + AC()), typeid(Expected));
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    namespace simd_abi = std::experimental::simd_abi;
+    binary_op_return_type<V, V, V>();
+    binary_op_return_type<V, T, V>();
+    binary_op_return_type<V, int, V>();
+
+    if constexpr (std::is_same_v<V, vfloat>)
+      {
+	binary_op_return_type<vfloat, schar>();
+	binary_op_return_type<vfloat, uchar>();
+	binary_op_return_type<vfloat, short>();
+	binary_op_return_type<vfloat, ushort>();
+
+	binary_op_return_type<vf32<float>, schar>();
+	binary_op_return_type<vf32<float>, uchar>();
+	binary_op_return_type<vf32<float>, short>();
+	binary_op_return_type<vf32<float>, ushort>();
+	binary_op_return_type<vf32<float>, int>();
+	binary_op_return_type<vf32<float>, float>();
+
+	binary_op_return_type<vf32<float>, vf32<schar>>();
+	binary_op_return_type<vf32<float>, vf32<uchar>>();
+	binary_op_return_type<vf32<float>, vf32<short>>();
+	binary_op_return_type<vf32<float>, vf32<ushort>>();
+	binary_op_return_type<vf32<float>, vf32<float>>();
+
+	VERIFY((is_substitution_failure<vfloat, uint>));
+	VERIFY((is_substitution_failure<vfloat, long>));
+	VERIFY((is_substitution_failure<vfloat, ulong>));
+	VERIFY((is_substitution_failure<vfloat, llong>));
+	VERIFY((is_substitution_failure<vfloat, ullong>));
+	VERIFY((is_substitution_failure<vfloat, double>));
+	VERIFY((is_substitution_failure<vfloat, vf32<schar>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<uchar>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<short>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<ushort>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<int>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<uint>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<long>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<ulong>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<llong>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<ullong>>));
+	VERIFY((is_substitution_failure<vfloat, vf32<float>>));
+
+	VERIFY((is_substitution_failure<vf32<float>, vfloat>));
+	VERIFY((is_substitution_failure<vf32<float>, uint>));
+	VERIFY((is_substitution_failure<vf32<float>, long>));
+	VERIFY((is_substitution_failure<vf32<float>, ulong>));
+	VERIFY((is_substitution_failure<vf32<float>, llong>));
+	VERIFY((is_substitution_failure<vf32<float>, ullong>));
+	VERIFY((is_substitution_failure<vf32<float>, double>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<int>>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<uint>>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<long>>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<ulong>>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<llong>>));
+	VERIFY((is_substitution_failure<vf32<float>, vf32<ullong>>));
+
+	VERIFY((is_substitution_failure<vfloat, vf32<double>>));
+      }
+    else if constexpr (std::is_same_v<V, vdouble>)
+      {
+	binary_op_return_type<vdouble, float, vdouble>();
+	binary_op_return_type<vdouble, schar>();
+	binary_op_return_type<vdouble, uchar>();
+	binary_op_return_type<vdouble, short>();
+	binary_op_return_type<vdouble, ushort>();
+	binary_op_return_type<vdouble, uint>();
+
+	binary_op_return_type<vf64<double>, schar>();
+	binary_op_return_type<vf64<double>, uchar>();
+	binary_op_return_type<vf64<double>, short>();
+	binary_op_return_type<vf64<double>, ushort>();
+	binary_op_return_type<vf64<double>, uint>();
+	binary_op_return_type<vf64<double>, int, vf64<double>>();
+	binary_op_return_type<vf64<double>, float, vf64<double>>();
+	binary_op_return_type<vf64<double>, double, vf64<double>>();
+	binary_op_return_type<vf64<double>, vf64<double>, vf64<double>>();
+	binary_op_return_type<vf32<double>, schar>();
+	binary_op_return_type<vf32<double>, uchar>();
+	binary_op_return_type<vf32<double>, short>();
+	binary_op_return_type<vf32<double>, ushort>();
+	binary_op_return_type<vf32<double>, uint>();
+	binary_op_return_type<vf32<double>, int, vf32<double>>();
+	binary_op_return_type<vf32<double>, float, vf32<double>>();
+	binary_op_return_type<vf32<double>, double, vf32<double>>();
+	binary_op_return_type<vf64<double>, vf64<schar>>();
+	binary_op_return_type<vf64<double>, vf64<uchar>>();
+	binary_op_return_type<vf64<double>, vf64<short>>();
+	binary_op_return_type<vf64<double>, vf64<ushort>>();
+	binary_op_return_type<vf64<double>, vf64<int>>();
+	binary_op_return_type<vf64<double>, vf64<uint>>();
+	binary_op_return_type<vf64<double>, vf64<float>>();
+
+	VERIFY((is_substitution_failure<vdouble, llong>));
+	VERIFY((is_substitution_failure<vdouble, ullong>));
+	VERIFY((is_substitution_failure<vdouble, vf64<schar>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<uchar>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<short>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<ushort>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<int>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<uint>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<long>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<ulong>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<llong>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<ullong>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<float>>));
+	VERIFY((is_substitution_failure<vdouble, vf64<double>>));
+
+	VERIFY((is_substitution_failure<vf64<double>, vdouble>));
+	VERIFY((is_substitution_failure<vf64<double>, llong>));
+	VERIFY((is_substitution_failure<vf64<double>, ullong>));
+	VERIFY((is_substitution_failure<vf64<double>, vf64<llong>>));
+	VERIFY((is_substitution_failure<vf64<double>, vf64<ullong>>));
+
+	VERIFY((is_substitution_failure<vf32<double>, llong>));
+	VERIFY((is_substitution_failure<vf32<double>, ullong>));
+
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    VERIFY((is_substitution_failure<vdouble, long>));
+	    VERIFY((is_substitution_failure<vdouble, ulong>));
+	    VERIFY((is_substitution_failure<vf64<double>, long>));
+	    VERIFY((is_substitution_failure<vf64<double>, ulong>));
+	    VERIFY((is_substitution_failure<vf64<double>, vf64<long>>));
+	    VERIFY((is_substitution_failure<vf64<double>, vf64<ulong>>));
+	    VERIFY((is_substitution_failure<vf32<double>, long>));
+	    VERIFY((is_substitution_failure<vf32<double>, ulong>));
+	  }
+	else
+	  {
+	    binary_op_return_type<vdouble, long>();
+	    binary_op_return_type<vdouble, ulong>();
+	    binary_op_return_type<vf64<double>, long>();
+	    binary_op_return_type<vf64<double>, ulong>();
+	    binary_op_return_type<vf64<double>, vf64<long>>();
+	    binary_op_return_type<vf64<double>, vf64<ulong>>();
+	    binary_op_return_type<vf32<double>, long>();
+	    binary_op_return_type<vf32<double>, ulong>();
+	  }
+      }
+    else if constexpr (std::is_same_v<V, vldouble>)
+      {
+	binary_op_return_type<vldouble, schar>();
+	binary_op_return_type<vldouble, uchar>();
+	binary_op_return_type<vldouble, short>();
+	binary_op_return_type<vldouble, ushort>();
+	binary_op_return_type<vldouble, uint>();
+	binary_op_return_type<vldouble, long>();
+	binary_op_return_type<vldouble, ulong>();
+	binary_op_return_type<vldouble, float>();
+	binary_op_return_type<vldouble, double>();
+
+	binary_op_return_type<vf64<long double>, schar>();
+	binary_op_return_type<vf64<long double>, uchar>();
+	binary_op_return_type<vf64<long double>, short>();
+	binary_op_return_type<vf64<long double>, ushort>();
+	binary_op_return_type<vf64<long double>, int>();
+	binary_op_return_type<vf64<long double>, uint>();
+	binary_op_return_type<vf64<long double>, long>();
+	binary_op_return_type<vf64<long double>, ulong>();
+	binary_op_return_type<vf64<long double>, float>();
+	binary_op_return_type<vf64<long double>, double>();
+	binary_op_return_type<vf64<long double>, vf64<long double>>();
+
+	using std::experimental::simd;
+	using A = simd_abi::fixed_size<vldouble::size()>;
+	binary_op_return_type<simd<long double, A>, schar>();
+	binary_op_return_type<simd<long double, A>, uchar>();
+	binary_op_return_type<simd<long double, A>, short>();
+	binary_op_return_type<simd<long double, A>, ushort>();
+	binary_op_return_type<simd<long double, A>, int>();
+	binary_op_return_type<simd<long double, A>, uint>();
+	binary_op_return_type<simd<long double, A>, long>();
+	binary_op_return_type<simd<long double, A>, ulong>();
+	binary_op_return_type<simd<long double, A>, float>();
+	binary_op_return_type<simd<long double, A>, double>();
+
+	if constexpr (sizeof(ldouble) == sizeof(double))
+	  {
+	    VERIFY((is_substitution_failure<vldouble, llong>));
+	    VERIFY((is_substitution_failure<vldouble, ullong>));
+	    VERIFY((is_substitution_failure<vf64<ldouble>, llong>));
+	    VERIFY((is_substitution_failure<vf64<ldouble>, ullong>));
+	    VERIFY((is_substitution_failure<simd<ldouble, A>, llong>));
+	    VERIFY((is_substitution_failure<simd<ldouble, A>, ullong>));
+	  }
+	else
+	  {
+	    binary_op_return_type<vldouble, llong>();
+	    binary_op_return_type<vldouble, ullong>();
+	    binary_op_return_type<vf64<long double>, llong>();
+	    binary_op_return_type<vf64<long double>, ullong>();
+	    binary_op_return_type<simd<long double, A>, llong>();
+	    binary_op_return_type<simd<long double, A>, ullong>();
+	  }
+
+	VERIFY((is_substitution_failure<vf64<long double>, vldouble>));
+	COMPARE((is_substitution_failure<simd<long double, A>, vldouble>),
+		(!std::is_same<A, vldouble::abi_type>::value));
+      }
+    else if constexpr (std::is_same_v<V, vlong>)
+      {
+	VERIFY((is_substitution_failure<vi32<long>, double>));
+	VERIFY((is_substitution_failure<vi32<long>, float>));
+	VERIFY((is_substitution_failure<vi32<long>, vi32<float>>));
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    binary_op_return_type<vlong, uint>();
+	    binary_op_return_type<vlong, llong>();
+	    binary_op_return_type<vi32<long>, uint>();
+	    binary_op_return_type<vi32<long>, llong>();
+	    binary_op_return_type<vi64<long>, uint>();
+	    binary_op_return_type<vi64<long>, llong>();
+	    binary_op_return_type<vi32<long>, vi32<uint>>();
+	    binary_op_return_type<vi64<long>, vi64<uint>>();
+	    VERIFY((is_substitution_failure<vi32<long>, vi32<double>>));
+	    VERIFY((is_substitution_failure<vi64<long>, vi64<double>>));
+	  }
+	else
+	  {
+	    VERIFY((is_substitution_failure<vlong, uint>));
+	    VERIFY((is_substitution_failure<vlong, llong>));
+	    VERIFY((is_substitution_failure<vi32<long>, uint>));
+	    VERIFY((is_substitution_failure<vi32<long>, llong>));
+	    VERIFY((is_substitution_failure<vi64<long>, uint>));
+	    VERIFY((is_substitution_failure<vi64<long>, llong>));
+	    VERIFY((is_substitution_failure<vi32<long>, vi32<uint>>));
+	    VERIFY((is_substitution_failure<vi64<long>, vi64<uint>>));
+	    binary_op_return_type<vi32<double>, vi32<long>>();
+	    binary_op_return_type<vi64<double>, vi64<long>>();
+	  }
+
+	binary_op_return_type<vlong, schar, vlong>();
+	binary_op_return_type<vlong, uchar, vlong>();
+	binary_op_return_type<vlong, short, vlong>();
+	binary_op_return_type<vlong, ushort, vlong>();
+
+	binary_op_return_type<vi32<long>, schar, vi32<long>>();
+	binary_op_return_type<vi32<long>, uchar, vi32<long>>();
+	binary_op_return_type<vi32<long>, short, vi32<long>>();
+	binary_op_return_type<vi32<long>, ushort, vi32<long>>();
+	binary_op_return_type<vi32<long>, int, vi32<long>>();
+	binary_op_return_type<vi32<long>, long, vi32<long>>();
+	binary_op_return_type<vi32<long>, vi32<long>, vi32<long>>();
+	binary_op_return_type<vi64<long>, schar, vi64<long>>();
+	binary_op_return_type<vi64<long>, uchar, vi64<long>>();
+	binary_op_return_type<vi64<long>, short, vi64<long>>();
+	binary_op_return_type<vi64<long>, ushort, vi64<long>>();
+	binary_op_return_type<vi64<long>, int, vi64<long>>();
+	binary_op_return_type<vi64<long>, long, vi64<long>>();
+	binary_op_return_type<vi64<long>, vi64<long>, vi64<long>>();
+
+	VERIFY((is_substitution_failure<vlong, vulong>));
+	VERIFY((is_substitution_failure<vlong, ulong>));
+	VERIFY((is_substitution_failure<vlong, ullong>));
+	VERIFY((is_substitution_failure<vlong, float>));
+	VERIFY((is_substitution_failure<vlong, double>));
+	VERIFY((is_substitution_failure<vlong, vl<schar>>));
+	VERIFY((is_substitution_failure<vlong, vl<uchar>>));
+	VERIFY((is_substitution_failure<vlong, vl<short>>));
+	VERIFY((is_substitution_failure<vlong, vl<ushort>>));
+	VERIFY((is_substitution_failure<vlong, vl<int>>));
+	VERIFY((is_substitution_failure<vlong, vl<uint>>));
+	VERIFY((is_substitution_failure<vlong, vl<long>>));
+	VERIFY((is_substitution_failure<vlong, vl<ulong>>));
+	VERIFY((is_substitution_failure<vlong, vl<llong>>));
+	VERIFY((is_substitution_failure<vlong, vl<ullong>>));
+	VERIFY((is_substitution_failure<vlong, vl<float>>));
+	VERIFY((is_substitution_failure<vlong, vl<double>>));
+	VERIFY((is_substitution_failure<vl<long>, vlong>));
+	VERIFY((is_substitution_failure<vl<long>, vulong>));
+	VERIFY((is_substitution_failure<vi32<long>, ulong>));
+	VERIFY((is_substitution_failure<vi32<long>, ullong>));
+	binary_op_return_type<vi32<long>, vi32<schar>>();
+	binary_op_return_type<vi32<long>, vi32<uchar>>();
+	binary_op_return_type<vi32<long>, vi32<short>>();
+	binary_op_return_type<vi32<long>, vi32<ushort>>();
+	binary_op_return_type<vi32<long>, vi32<int>>();
+	VERIFY((is_substitution_failure<vi32<long>, vi32<ulong>>));
+	VERIFY((is_substitution_failure<vi32<long>, vi32<ullong>>));
+	VERIFY((is_substitution_failure<vi64<long>, ulong>));
+	VERIFY((is_substitution_failure<vi64<long>, ullong>));
+	VERIFY((is_substitution_failure<vi64<long>, float>));
+	VERIFY((is_substitution_failure<vi64<long>, double>));
+	binary_op_return_type<vi64<long>, vi64<schar>>();
+	binary_op_return_type<vi64<long>, vi64<uchar>>();
+	binary_op_return_type<vi64<long>, vi64<short>>();
+	binary_op_return_type<vi64<long>, vi64<ushort>>();
+	binary_op_return_type<vi64<long>, vi64<int>>();
+	VERIFY((is_substitution_failure<vi64<long>, vi64<ulong>>));
+	VERIFY((is_substitution_failure<vi64<long>, vi64<ullong>>));
+	VERIFY((is_substitution_failure<vi64<long>, vi64<float>>));
+
+	binary_op_return_type<vi32<llong>, vi32<long>>();
+	binary_op_return_type<vi64<llong>, vi64<long>>();
+      }
+    else if constexpr (std::is_same_v<V, vulong>)
+      {
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    binary_op_return_type<vulong, ullong, vulong>();
+	    binary_op_return_type<vi32<ulong>, ullong, vi32<ulong>>();
+	    binary_op_return_type<vi64<ulong>, ullong, vi64<ulong>>();
+	    VERIFY((is_substitution_failure<vi32<ulong>, vi32<llong>>));
+	    VERIFY((is_substitution_failure<vi32<ulong>, vi32<double>>));
+	    VERIFY((is_substitution_failure<vi64<ulong>, vi64<llong>>));
+	    VERIFY((is_substitution_failure<vi64<ulong>, vi64<double>>));
+	  }
+	else
+	  {
+	    VERIFY((is_substitution_failure<vulong, ullong>));
+	    VERIFY((is_substitution_failure<vi32<ulong>, ullong>));
+	    VERIFY((is_substitution_failure<vi64<ulong>, ullong>));
+	    binary_op_return_type<vi32<llong>, vi32<ulong>>();
+	    binary_op_return_type<vi32<double>, vi32<ulong>>();
+	    binary_op_return_type<vi64<llong>, vi64<ulong>>();
+	    binary_op_return_type<vi64<double>, vi64<ulong>>();
+	  }
+
+	binary_op_return_type<vulong, uchar, vulong>();
+	binary_op_return_type<vulong, ushort, vulong>();
+	binary_op_return_type<vulong, uint, vulong>();
+	binary_op_return_type<vi32<ulong>, uchar, vi32<ulong>>();
+	binary_op_return_type<vi32<ulong>, ushort, vi32<ulong>>();
+	binary_op_return_type<vi32<ulong>, int, vi32<ulong>>();
+	binary_op_return_type<vi32<ulong>, uint, vi32<ulong>>();
+	binary_op_return_type<vi32<ulong>, ulong, vi32<ulong>>();
+	binary_op_return_type<vi32<ulong>, vi32<ulong>, vi32<ulong>>();
+	binary_op_return_type<vi64<ulong>, uchar, vi64<ulong>>();
+	binary_op_return_type<vi64<ulong>, ushort, vi64<ulong>>();
+	binary_op_return_type<vi64<ulong>, int, vi64<ulong>>();
+	binary_op_return_type<vi64<ulong>, uint, vi64<ulong>>();
+	binary_op_return_type<vi64<ulong>, ulong, vi64<ulong>>();
+	binary_op_return_type<vi64<ulong>, vi64<ulong>, vi64<ulong>>();
+
+	VERIFY((is_substitution_failure<vi32<ulong>, llong>));
+	VERIFY((is_substitution_failure<vi32<ulong>, float>));
+	VERIFY((is_substitution_failure<vi32<ulong>, double>));
+	VERIFY((is_substitution_failure<vi32<ulong>, vi32<float>>));
+	VERIFY((is_substitution_failure<vi64<ulong>, vi64<float>>));
+	VERIFY((is_substitution_failure<vulong, schar>));
+	VERIFY((is_substitution_failure<vulong, short>));
+	VERIFY((is_substitution_failure<vulong, vlong>));
+	VERIFY((is_substitution_failure<vulong, long>));
+	VERIFY((is_substitution_failure<vulong, llong>));
+	VERIFY((is_substitution_failure<vulong, float>));
+	VERIFY((is_substitution_failure<vulong, double>));
+	VERIFY((is_substitution_failure<vulong, vl<schar>>));
+	VERIFY((is_substitution_failure<vulong, vl<uchar>>));
+	VERIFY((is_substitution_failure<vulong, vl<short>>));
+	VERIFY((is_substitution_failure<vulong, vl<ushort>>));
+	VERIFY((is_substitution_failure<vulong, vl<int>>));
+	VERIFY((is_substitution_failure<vulong, vl<uint>>));
+	VERIFY((is_substitution_failure<vulong, vl<long>>));
+	VERIFY((is_substitution_failure<vulong, vl<ulong>>));
+	VERIFY((is_substitution_failure<vulong, vl<llong>>));
+	VERIFY((is_substitution_failure<vulong, vl<ullong>>));
+	VERIFY((is_substitution_failure<vulong, vl<float>>));
+	VERIFY((is_substitution_failure<vulong, vl<double>>));
+	VERIFY((is_substitution_failure<vl<ulong>, vlong>));
+	VERIFY((is_substitution_failure<vl<ulong>, vulong>));
+	VERIFY((is_substitution_failure<vi32<ulong>, schar>));
+	VERIFY((is_substitution_failure<vi32<ulong>, short>));
+	VERIFY((is_substitution_failure<vi32<ulong>, long>));
+	VERIFY((is_substitution_failure<vi32<ulong>, vi32<schar>>));
+	binary_op_return_type<vi32<ulong>, vi32<uchar>>();
+	VERIFY((is_substitution_failure<vi32<ulong>, vi32<short>>));
+	binary_op_return_type<vi32<ulong>, vi32<ushort>>();
+	VERIFY((is_substitution_failure<vi32<ulong>, vi32<int>>));
+	binary_op_return_type<vi32<ulong>, vi32<uint>>();
+	VERIFY((is_substitution_failure<vi32<ulong>, vi32<long>>));
+	binary_op_return_type<vi32<ullong>, vi32<ulong>>();
+	VERIFY((is_substitution_failure<vi64<ulong>, schar>));
+	VERIFY((is_substitution_failure<vi64<ulong>, short>));
+	VERIFY((is_substitution_failure<vi64<ulong>, long>));
+	VERIFY((is_substitution_failure<vi64<ulong>, llong>));
+	VERIFY((is_substitution_failure<vi64<ulong>, float>));
+	VERIFY((is_substitution_failure<vi64<ulong>, double>));
+	VERIFY((is_substitution_failure<vi64<ulong>, vi64<schar>>));
+	binary_op_return_type<vi64<ulong>, vi64<uchar>>();
+	VERIFY((is_substitution_failure<vi64<ulong>, vi64<short>>));
+	binary_op_return_type<vi64<ulong>, vi64<ushort>>();
+	VERIFY((is_substitution_failure<vi64<ulong>, vi64<int>>));
+	binary_op_return_type<vi64<ulong>, vi64<uint>>();
+	VERIFY((is_substitution_failure<vi64<ulong>, vi64<long>>));
+	binary_op_return_type<vi64<ullong>, vi64<ulong>>();
+      }
+    else if constexpr (std::is_same_v<V, vllong>)
+      {
+	binary_op_return_type<vllong, schar, vllong>();
+	binary_op_return_type<vllong, uchar, vllong>();
+	binary_op_return_type<vllong, short, vllong>();
+	binary_op_return_type<vllong, ushort, vllong>();
+	binary_op_return_type<vllong, uint, vllong>();
+	binary_op_return_type<vllong, long, vllong>();
+	binary_op_return_type<vi32<llong>, schar, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, uchar, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, short, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, ushort, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, int, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, uint, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, long, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, llong, vi32<llong>>();
+	binary_op_return_type<vi32<llong>, vi32<llong>, vi32<llong>>();
+	binary_op_return_type<vi64<llong>, schar, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, uchar, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, short, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, ushort, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, int, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, uint, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, long, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, llong, vi64<llong>>();
+	binary_op_return_type<vi64<llong>, vi64<llong>>();
+	binary_op_return_type<vi32<llong>, vi32<schar>>();
+	binary_op_return_type<vi32<llong>, vi32<uchar>>();
+	binary_op_return_type<vi32<llong>, vi32<short>>();
+	binary_op_return_type<vi32<llong>, vi32<ushort>>();
+	binary_op_return_type<vi32<llong>, vi32<int>>();
+	binary_op_return_type<vi32<llong>, vi32<uint>>();
+	binary_op_return_type<vi32<llong>, vi32<long>>();
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    VERIFY((is_substitution_failure<vi32<llong>, vi32<ulong>>));
+	    VERIFY((is_substitution_failure<vi32<llong>, ulong>));
+	    VERIFY((is_substitution_failure<vi64<llong>, ulong>));
+	    VERIFY((is_substitution_failure<vllong, ulong>));
+	  }
+	else
+	  {
+	    binary_op_return_type<vi32<llong>, vi32<ulong>>();
+	    binary_op_return_type<vi32<llong>, ulong>();
+	    binary_op_return_type<vi64<llong>, ulong>();
+	    binary_op_return_type<vllong, ulong>();
+	  }
+
+	VERIFY((is_substitution_failure<vllong, vullong>));
+	VERIFY((is_substitution_failure<vllong, ullong>));
+	VERIFY((is_substitution_failure<vllong, float>));
+	VERIFY((is_substitution_failure<vllong, double>));
+	VERIFY((is_substitution_failure<vllong, vi64<schar>>));
+	VERIFY((is_substitution_failure<vllong, vi64<uchar>>));
+	VERIFY((is_substitution_failure<vllong, vi64<short>>));
+	VERIFY((is_substitution_failure<vllong, vi64<ushort>>));
+	VERIFY((is_substitution_failure<vllong, vi64<int>>));
+	VERIFY((is_substitution_failure<vllong, vi64<uint>>));
+	VERIFY((is_substitution_failure<vllong, vi64<long>>));
+	VERIFY((is_substitution_failure<vllong, vi64<ulong>>));
+	VERIFY((is_substitution_failure<vllong, vi64<llong>>));
+	VERIFY((is_substitution_failure<vllong, vi64<ullong>>));
+	VERIFY((is_substitution_failure<vllong, vi64<float>>));
+	VERIFY((is_substitution_failure<vllong, vi64<double>>));
+	VERIFY((is_substitution_failure<vi32<llong>, ullong>));
+	VERIFY((is_substitution_failure<vi32<llong>, float>));
+	VERIFY((is_substitution_failure<vi32<llong>, double>));
+	VERIFY((is_substitution_failure<vi32<llong>, vi32<ullong>>));
+	VERIFY((is_substitution_failure<vi32<llong>, vi32<float>>));
+	VERIFY((is_substitution_failure<vi32<llong>, vi32<double>>));
+	VERIFY((is_substitution_failure<vi64<llong>, vllong>));
+	VERIFY((is_substitution_failure<vi64<llong>, vullong>));
+	VERIFY((is_substitution_failure<vi64<llong>, ullong>));
+	VERIFY((is_substitution_failure<vi64<llong>, float>));
+	VERIFY((is_substitution_failure<vi64<llong>, double>));
+	binary_op_return_type<vi64<llong>, vi64<schar>>();
+	binary_op_return_type<vi64<llong>, vi64<uchar>>();
+	binary_op_return_type<vi64<llong>, vi64<short>>();
+	binary_op_return_type<vi64<llong>, vi64<ushort>>();
+	binary_op_return_type<vi64<llong>, vi64<int>>();
+	binary_op_return_type<vi64<llong>, vi64<uint>>();
+	binary_op_return_type<vi64<llong>, vi64<long>>();
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    VERIFY((is_substitution_failure<vi64<llong>, vi64<ulong>>));
+	  }
+	else
+	  {
+	    binary_op_return_type<vi64<llong>, vi64<ulong>>();
+	  }
+	VERIFY((is_substitution_failure<vi64<llong>, vi64<ullong>>));
+	VERIFY((is_substitution_failure<vi64<llong>, vi64<float>>));
+	VERIFY((is_substitution_failure<vi64<llong>, vi64<double>>));
+      }
+    else if constexpr (std::is_same_v<V, vullong>)
+      {
+	binary_op_return_type<vullong, uchar, vullong>();
+	binary_op_return_type<vullong, ushort, vullong>();
+	binary_op_return_type<vullong, uint, vullong>();
+	binary_op_return_type<vullong, ulong, vullong>();
+	binary_op_return_type<vi32<ullong>, uchar, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, ushort, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, int, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, uint, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, ulong, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, ullong, vi32<ullong>>();
+	binary_op_return_type<vi32<ullong>, vi32<ullong>, vi32<ullong>>();
+	binary_op_return_type<vi64<ullong>, uchar, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, ushort, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, int, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, uint, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, ulong, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, ullong, vi64<ullong>>();
+	binary_op_return_type<vi64<ullong>, vi64<ullong>, vi64<ullong>>();
+
+	VERIFY((is_substitution_failure<vullong, schar>));
+	VERIFY((is_substitution_failure<vullong, short>));
+	VERIFY((is_substitution_failure<vullong, long>));
+	VERIFY((is_substitution_failure<vullong, llong>));
+	VERIFY((is_substitution_failure<vullong, vllong>));
+	VERIFY((is_substitution_failure<vullong, float>));
+	VERIFY((is_substitution_failure<vullong, double>));
+	VERIFY((is_substitution_failure<vullong, vi64<schar>>));
+	VERIFY((is_substitution_failure<vullong, vi64<uchar>>));
+	VERIFY((is_substitution_failure<vullong, vi64<short>>));
+	VERIFY((is_substitution_failure<vullong, vi64<ushort>>));
+	VERIFY((is_substitution_failure<vullong, vi64<int>>));
+	VERIFY((is_substitution_failure<vullong, vi64<uint>>));
+	VERIFY((is_substitution_failure<vullong, vi64<long>>));
+	VERIFY((is_substitution_failure<vullong, vi64<ulong>>));
+	VERIFY((is_substitution_failure<vullong, vi64<llong>>));
+	VERIFY((is_substitution_failure<vullong, vi64<ullong>>));
+	VERIFY((is_substitution_failure<vullong, vi64<float>>));
+	VERIFY((is_substitution_failure<vullong, vi64<double>>));
+	VERIFY((is_substitution_failure<vi32<ullong>, schar>));
+	VERIFY((is_substitution_failure<vi32<ullong>, short>));
+	VERIFY((is_substitution_failure<vi32<ullong>, long>));
+	VERIFY((is_substitution_failure<vi32<ullong>, llong>));
+	VERIFY((is_substitution_failure<vi32<ullong>, float>));
+	VERIFY((is_substitution_failure<vi32<ullong>, double>));
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<schar>>));
+	binary_op_return_type<vi32<ullong>, vi32<uchar>>();
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<short>>));
+	binary_op_return_type<vi32<ullong>, vi32<ushort>>();
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<int>>));
+	binary_op_return_type<vi32<ullong>, vi32<uint>>();
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<long>>));
+	binary_op_return_type<vi32<ullong>, vi32<ulong>>();
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<llong>>));
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<float>>));
+	VERIFY((is_substitution_failure<vi32<ullong>, vi32<double>>));
+	VERIFY((is_substitution_failure<vi64<ullong>, schar>));
+	VERIFY((is_substitution_failure<vi64<ullong>, short>));
+	VERIFY((is_substitution_failure<vi64<ullong>, long>));
+	VERIFY((is_substitution_failure<vi64<ullong>, llong>));
+	VERIFY((is_substitution_failure<vi64<ullong>, vllong>));
+	VERIFY((is_substitution_failure<vi64<ullong>, vullong>));
+	VERIFY((is_substitution_failure<vi64<ullong>, float>));
+	VERIFY((is_substitution_failure<vi64<ullong>, double>));
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<schar>>));
+	binary_op_return_type<vi64<ullong>, vi64<uchar>>();
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<short>>));
+	binary_op_return_type<vi64<ullong>, vi64<ushort>>();
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<int>>));
+	binary_op_return_type<vi64<ullong>, vi64<uint>>();
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<long>>));
+	binary_op_return_type<vi64<ullong>, vi64<ulong>>();
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<llong>>));
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<float>>));
+	VERIFY((is_substitution_failure<vi64<ullong>, vi64<double>>));
+      }
+    else if constexpr (std::is_same_v<V, vint>)
+      {
+	binary_op_return_type<vint, schar, vint>();
+	binary_op_return_type<vint, uchar, vint>();
+	binary_op_return_type<vint, short, vint>();
+	binary_op_return_type<vint, ushort, vint>();
+	binary_op_return_type<vi32<int>, schar, vi32<int>>();
+	binary_op_return_type<vi32<int>, uchar, vi32<int>>();
+	binary_op_return_type<vi32<int>, short, vi32<int>>();
+	binary_op_return_type<vi32<int>, ushort, vi32<int>>();
+	binary_op_return_type<vi32<int>, int, vi32<int>>();
+	binary_op_return_type<vi32<int>, vi32<int>, vi32<int>>();
+	binary_op_return_type<vi32<int>, vi32<schar>>();
+	binary_op_return_type<vi32<int>, vi32<uchar>>();
+	binary_op_return_type<vi32<int>, vi32<short>>();
+	binary_op_return_type<vi32<int>, vi32<ushort>>();
+
+	binary_op_return_type<vi32<llong>, vi32<int>>();
+	binary_op_return_type<vi32<double>, vi32<int>>();
+
+	// order is important for MSVC. This compiler is just crazy: It considers
+	// operators from unrelated simd template instantiations as candidates -
+	// but only after they have been tested. So e.g. vi32<int> + llong will
+	// produce a vi32<llong> if a vi32<llong> operator test is done before the
+	// vi32<int> + llong test.
+	VERIFY((is_substitution_failure<vi32<int>, double>));
+	VERIFY((is_substitution_failure<vi32<int>, float>));
+	VERIFY((is_substitution_failure<vi32<int>, llong>));
+	VERIFY((is_substitution_failure<vi32<int>, vi32<float>>));
+	VERIFY((is_substitution_failure<vint, vuint>));
+	VERIFY((is_substitution_failure<vint, uint>));
+	VERIFY((is_substitution_failure<vint, ulong>));
+	VERIFY((is_substitution_failure<vint, llong>));
+	VERIFY((is_substitution_failure<vint, ullong>));
+	VERIFY((is_substitution_failure<vint, float>));
+	VERIFY((is_substitution_failure<vint, double>));
+	VERIFY((is_substitution_failure<vint, vi32<schar>>));
+	VERIFY((is_substitution_failure<vint, vi32<uchar>>));
+	VERIFY((is_substitution_failure<vint, vi32<short>>));
+	VERIFY((is_substitution_failure<vint, vi32<ushort>>));
+	VERIFY((is_substitution_failure<vint, vi32<int>>));
+	VERIFY((is_substitution_failure<vint, vi32<uint>>));
+	VERIFY((is_substitution_failure<vint, vi32<long>>));
+	VERIFY((is_substitution_failure<vint, vi32<ulong>>));
+	VERIFY((is_substitution_failure<vint, vi32<llong>>));
+	VERIFY((is_substitution_failure<vint, vi32<ullong>>));
+	VERIFY((is_substitution_failure<vint, vi32<float>>));
+	VERIFY((is_substitution_failure<vint, vi32<double>>));
+	VERIFY((is_substitution_failure<vi32<int>, vint>));
+	VERIFY((is_substitution_failure<vi32<int>, vuint>));
+	VERIFY((is_substitution_failure<vi32<int>, uint>));
+	VERIFY((is_substitution_failure<vi32<int>, ulong>));
+	VERIFY((is_substitution_failure<vi32<int>, ullong>));
+	VERIFY((is_substitution_failure<vi32<int>, vi32<uint>>));
+	VERIFY((is_substitution_failure<vi32<int>, vi32<ulong>>));
+	VERIFY((is_substitution_failure<vi32<int>, vi32<ullong>>));
+
+	binary_op_return_type<vi32<long>, vi32<int>>();
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    VERIFY((is_substitution_failure<vint, long>));
+	    VERIFY((is_substitution_failure<vi32<int>, long>));
+	  }
+	else
+	  {
+	    binary_op_return_type<vint, long>();
+	    binary_op_return_type<vi32<int>, long>();
+	  }
+      }
+    else if constexpr (std::is_same_v<V, vuint>)
+      {
+	VERIFY((is_substitution_failure<vi32<uint>, llong>));
+	VERIFY((is_substitution_failure<vi32<uint>, ullong>));
+	VERIFY((is_substitution_failure<vi32<uint>, float>));
+	VERIFY((is_substitution_failure<vi32<uint>, double>));
+	VERIFY((is_substitution_failure<vi32<uint>, vi32<float>>));
+
+	binary_op_return_type<vuint, uchar, vuint>();
+	binary_op_return_type<vuint, ushort, vuint>();
+	binary_op_return_type<vi32<uint>, uchar, vi32<uint>>();
+	binary_op_return_type<vi32<uint>, ushort, vi32<uint>>();
+	binary_op_return_type<vi32<uint>, int, vi32<uint>>();
+	binary_op_return_type<vi32<uint>, uint, vi32<uint>>();
+	binary_op_return_type<vi32<uint>, vi32<uint>, vi32<uint>>();
+	binary_op_return_type<vi32<uint>, vi32<uchar>>();
+	binary_op_return_type<vi32<uint>, vi32<ushort>>();
+
+	binary_op_return_type<vi32<llong>, vi32<uint>>();
+	binary_op_return_type<vi32<ullong>, vi32<uint>>();
+	binary_op_return_type<vi32<double>, vi32<uint>>();
+
+	VERIFY((is_substitution_failure<vuint, schar>));
+	VERIFY((is_substitution_failure<vuint, short>));
+	VERIFY((is_substitution_failure<vuint, vint>));
+	VERIFY((is_substitution_failure<vuint, long>));
+	VERIFY((is_substitution_failure<vuint, llong>));
+	VERIFY((is_substitution_failure<vuint, ullong>));
+	VERIFY((is_substitution_failure<vuint, float>));
+	VERIFY((is_substitution_failure<vuint, double>));
+	VERIFY((is_substitution_failure<vuint, vi32<schar>>));
+	VERIFY((is_substitution_failure<vuint, vi32<uchar>>));
+	VERIFY((is_substitution_failure<vuint, vi32<short>>));
+	VERIFY((is_substitution_failure<vuint, vi32<ushort>>));
+	VERIFY((is_substitution_failure<vuint, vi32<int>>));
+	VERIFY((is_substitution_failure<vuint, vi32<uint>>));
+	VERIFY((is_substitution_failure<vuint, vi32<long>>));
+	VERIFY((is_substitution_failure<vuint, vi32<ulong>>));
+	VERIFY((is_substitution_failure<vuint, vi32<llong>>));
+	VERIFY((is_substitution_failure<vuint, vi32<ullong>>));
+	VERIFY((is_substitution_failure<vuint, vi32<float>>));
+	VERIFY((is_substitution_failure<vuint, vi32<double>>));
+	VERIFY((is_substitution_failure<vi32<uint>, schar>));
+	VERIFY((is_substitution_failure<vi32<uint>, short>));
+	VERIFY((is_substitution_failure<vi32<uint>, vint>));
+	VERIFY((is_substitution_failure<vi32<uint>, vuint>));
+	VERIFY((is_substitution_failure<vi32<uint>, long>));
+	VERIFY((is_substitution_failure<vi32<uint>, vi32<schar>>));
+	VERIFY((is_substitution_failure<vi32<uint>, vi32<short>>));
+	VERIFY((is_substitution_failure<vi32<uint>, vi32<int>>));
+
+	binary_op_return_type<vi32<ulong>, vi32<uint>>();
+	if constexpr (sizeof(long) == sizeof(llong))
+	  {
+	    VERIFY((is_substitution_failure<vuint, ulong>));
+	    VERIFY((is_substitution_failure<vi32<uint>, ulong>));
+	    binary_op_return_type<vi32<long>, vi32<uint>>();
+	  }
+	else
+	  {
+	    binary_op_return_type<vuint, ulong>();
+	    binary_op_return_type<vi32<uint>, ulong>();
+	    VERIFY((is_substitution_failure<vi32<uint>, vi32<long>>));
+	  }
+      }
+    else if constexpr (std::is_same_v<V, vshort>)
+      {
+	binary_op_return_type<vshort, schar, vshort>();
+	binary_op_return_type<vshort, uchar, vshort>();
+	binary_op_return_type<vi16<short>, schar, vi16<short>>();
+	binary_op_return_type<vi16<short>, uchar, vi16<short>>();
+	binary_op_return_type<vi16<short>, short, vi16<short>>();
+	binary_op_return_type<vi16<short>, int, vi16<short>>();
+	binary_op_return_type<vi16<short>, vi16<schar>>();
+	binary_op_return_type<vi16<short>, vi16<uchar>>();
+	binary_op_return_type<vi16<short>, vi16<short>>();
+
+	binary_op_return_type<vi16<int>, vi16<short>>();
+	binary_op_return_type<vi16<long>, vi16<short>>();
+	binary_op_return_type<vi16<llong>, vi16<short>>();
+	binary_op_return_type<vi16<float>, vi16<short>>();
+	binary_op_return_type<vi16<double>, vi16<short>>();
+
+	VERIFY((is_substitution_failure<vi16<short>, double>));
+	VERIFY((is_substitution_failure<vi16<short>, llong>));
+	VERIFY((is_substitution_failure<vshort, vushort>));
+	VERIFY((is_substitution_failure<vshort, ushort>));
+	VERIFY((is_substitution_failure<vshort, uint>));
+	VERIFY((is_substitution_failure<vshort, long>));
+	VERIFY((is_substitution_failure<vshort, ulong>));
+	VERIFY((is_substitution_failure<vshort, llong>));
+	VERIFY((is_substitution_failure<vshort, ullong>));
+	VERIFY((is_substitution_failure<vshort, float>));
+	VERIFY((is_substitution_failure<vshort, double>));
+	VERIFY((is_substitution_failure<vshort, vi16<schar>>));
+	VERIFY((is_substitution_failure<vshort, vi16<uchar>>));
+	VERIFY((is_substitution_failure<vshort, vi16<short>>));
+	VERIFY((is_substitution_failure<vshort, vi16<ushort>>));
+	VERIFY((is_substitution_failure<vshort, vi16<int>>));
+	VERIFY((is_substitution_failure<vshort, vi16<uint>>));
+	VERIFY((is_substitution_failure<vshort, vi16<long>>));
+	VERIFY((is_substitution_failure<vshort, vi16<ulong>>));
+	VERIFY((is_substitution_failure<vshort, vi16<llong>>));
+	VERIFY((is_substitution_failure<vshort, vi16<ullong>>));
+	VERIFY((is_substitution_failure<vshort, vi16<float>>));
+	VERIFY((is_substitution_failure<vshort, vi16<double>>));
+	VERIFY((is_substitution_failure<vi16<short>, vshort>));
+	VERIFY((is_substitution_failure<vi16<short>, vushort>));
+	VERIFY((is_substitution_failure<vi16<short>, ushort>));
+	VERIFY((is_substitution_failure<vi16<short>, uint>));
+	VERIFY((is_substitution_failure<vi16<short>, long>));
+	VERIFY((is_substitution_failure<vi16<short>, ulong>));
+	VERIFY((is_substitution_failure<vi16<short>, ullong>));
+	VERIFY((is_substitution_failure<vi16<short>, float>));
+	VERIFY((is_substitution_failure<vi16<short>, vi16<ushort>>));
+	VERIFY((is_substitution_failure<vi16<short>, vi16<uint>>));
+	VERIFY((is_substitution_failure<vi16<short>, vi16<ulong>>));
+	VERIFY((is_substitution_failure<vi16<short>, vi16<ullong>>));
+      }
+    else if constexpr (std::is_same_v<V, vushort>)
+      {
+	binary_op_return_type<vushort, uchar, vushort>();
+	binary_op_return_type<vushort, uint, vushort>();
+	binary_op_return_type<vi16<ushort>, uchar, vi16<ushort>>();
+	binary_op_return_type<vi16<ushort>, ushort, vi16<ushort>>();
+	binary_op_return_type<vi16<ushort>, int, vi16<ushort>>();
+	binary_op_return_type<vi16<ushort>, uint, vi16<ushort>>();
+	binary_op_return_type<vi16<ushort>, vi16<uchar>>();
+	binary_op_return_type<vi16<ushort>, vi16<ushort>>();
+
+	binary_op_return_type<vi16<int>, vi16<ushort>>();
+	binary_op_return_type<vi16<long>, vi16<ushort>>();
+	binary_op_return_type<vi16<llong>, vi16<ushort>>();
+	binary_op_return_type<vi16<uint>, vi16<ushort>>();
+	binary_op_return_type<vi16<ulong>, vi16<ushort>>();
+	binary_op_return_type<vi16<ullong>, vi16<ushort>>();
+	binary_op_return_type<vi16<float>, vi16<ushort>>();
+	binary_op_return_type<vi16<double>, vi16<ushort>>();
+
+	VERIFY((is_substitution_failure<vi16<ushort>, llong>));
+	VERIFY((is_substitution_failure<vi16<ushort>, ullong>));
+	VERIFY((is_substitution_failure<vi16<ushort>, double>));
+	VERIFY((is_substitution_failure<vushort, schar>));
+	VERIFY((is_substitution_failure<vushort, short>));
+	VERIFY((is_substitution_failure<vushort, vshort>));
+	VERIFY((is_substitution_failure<vushort, long>));
+	VERIFY((is_substitution_failure<vushort, ulong>));
+	VERIFY((is_substitution_failure<vushort, llong>));
+	VERIFY((is_substitution_failure<vushort, ullong>));
+	VERIFY((is_substitution_failure<vushort, float>));
+	VERIFY((is_substitution_failure<vushort, double>));
+	VERIFY((is_substitution_failure<vushort, vi16<schar>>));
+	VERIFY((is_substitution_failure<vushort, vi16<uchar>>));
+	VERIFY((is_substitution_failure<vushort, vi16<short>>));
+	VERIFY((is_substitution_failure<vushort, vi16<ushort>>));
+	VERIFY((is_substitution_failure<vushort, vi16<int>>));
+	VERIFY((is_substitution_failure<vushort, vi16<uint>>));
+	VERIFY((is_substitution_failure<vushort, vi16<long>>));
+	VERIFY((is_substitution_failure<vushort, vi16<ulong>>));
+	VERIFY((is_substitution_failure<vushort, vi16<llong>>));
+	VERIFY((is_substitution_failure<vushort, vi16<ullong>>));
+	VERIFY((is_substitution_failure<vushort, vi16<float>>));
+	VERIFY((is_substitution_failure<vushort, vi16<double>>));
+	VERIFY((is_substitution_failure<vi16<ushort>, schar>));
+	VERIFY((is_substitution_failure<vi16<ushort>, short>));
+	VERIFY((is_substitution_failure<vi16<ushort>, vshort>));
+	VERIFY((is_substitution_failure<vi16<ushort>, vushort>));
+	VERIFY((is_substitution_failure<vi16<ushort>, long>));
+	VERIFY((is_substitution_failure<vi16<ushort>, ulong>));
+	VERIFY((is_substitution_failure<vi16<ushort>, float>));
+	VERIFY((is_substitution_failure<vi16<ushort>, vi16<schar>>));
+	VERIFY((is_substitution_failure<vi16<ushort>, vi16<short>>));
+      }
+    else if constexpr (std::is_same_v<V, vchar>)
+      {
+	binary_op_return_type<vi8<char>, char, vi8<char>>();
+	binary_op_return_type<vi8<char>, int, vi8<char>>();
+	binary_op_return_type<vi8<char>, vi8<char>, vi8<char>>();
+
+	if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+	  {
+	    VERIFY(!(is_substitution_failure<vi8<char>, vi8<short>>));
+	    VERIFY(!(is_substitution_failure<vi8<char>, vi8<int>>));
+	    VERIFY(!(is_substitution_failure<vi8<char>, vi8<long>>));
+	    VERIFY(!(is_substitution_failure<vi8<char>, vi8<llong>>));
+	    COMPARE((is_substitution_failure<vi8<char>, vi8<ushort>>),
+		    std::is_signed_v<char>);
+	    COMPARE((is_substitution_failure<vi8<char>, vi8<uint>>),
+		    std::is_signed_v<char>);
+	    COMPARE((is_substitution_failure<vi8<char>, vi8<ulong>>),
+		    std::is_signed_v<char>);
+	    COMPARE((is_substitution_failure<vi8<char>, vi8<ullong>>),
+		    std::is_signed_v<char>);
+	    if constexpr (std::is_signed_v<char>)
+	      {
+		binary_op_return_type<vi8<short>, vi8<char>>();
+		binary_op_return_type<vi8<int>, vi8<char>>();
+		binary_op_return_type<vi8<long>, vi8<char>>();
+		binary_op_return_type<vi8<llong>, vi8<char>>();
+	      }
+	    else
+	      {
+		binary_op_return_type<vi8<ushort>, vi8<char>>();
+		binary_op_return_type<vi8<uint>, vi8<char>>();
+		binary_op_return_type<vi8<ulong>, vi8<char>>();
+		binary_op_return_type<vi8<ullong>, vi8<char>>();
+	      }
+	    binary_op_return_type<vi8<float>, vi8<char>>();
+	    binary_op_return_type<vi8<double>, vi8<char>>();
+	  }
+
+	VERIFY((is_substitution_failure<vi8<char>, llong>));
+	VERIFY((is_substitution_failure<vi8<char>, double>));
+	VERIFY((is_substitution_failure<vchar, vxchar>));
+	VERIFY((is_substitution_failure<vchar, xchar>));
+	VERIFY((is_substitution_failure<vchar, short>));
+	VERIFY((is_substitution_failure<vchar, ushort>));
+	COMPARE((is_substitution_failure<vchar, uint>), std::is_signed_v<char>);
+	VERIFY((is_substitution_failure<vchar, long>));
+	VERIFY((is_substitution_failure<vchar, ulong>));
+	VERIFY((is_substitution_failure<vchar, llong>));
+	VERIFY((is_substitution_failure<vchar, ullong>));
+	VERIFY((is_substitution_failure<vchar, float>));
+	VERIFY((is_substitution_failure<vchar, double>));
+	VERIFY((is_substitution_failure<vchar, vi8<char>>));
+	VERIFY((is_substitution_failure<vchar, vi8<uchar>>));
+	VERIFY((is_substitution_failure<vchar, vi8<schar>>));
+	VERIFY((is_substitution_failure<vchar, vi8<short>>));
+	VERIFY((is_substitution_failure<vchar, vi8<ushort>>));
+	VERIFY((is_substitution_failure<vchar, vi8<int>>));
+	VERIFY((is_substitution_failure<vchar, vi8<uint>>));
+	VERIFY((is_substitution_failure<vchar, vi8<long>>));
+	VERIFY((is_substitution_failure<vchar, vi8<ulong>>));
+	VERIFY((is_substitution_failure<vchar, vi8<llong>>));
+	VERIFY((is_substitution_failure<vchar, vi8<ullong>>));
+	VERIFY((is_substitution_failure<vchar, vi8<float>>));
+	VERIFY((is_substitution_failure<vchar, vi8<double>>));
+	VERIFY((is_substitution_failure<vi8<char>, vchar>));
+	VERIFY((is_substitution_failure<vi8<char>, vuchar>));
+	VERIFY((is_substitution_failure<vi8<char>, vschar>));
+	VERIFY((is_substitution_failure<vi8<char>, xchar>));
+	VERIFY((is_substitution_failure<vi8<char>, short>));
+	VERIFY((is_substitution_failure<vi8<char>, ushort>));
+	COMPARE((is_substitution_failure<vi8<char>, uint>),
+		std::is_signed_v<char>);
+	VERIFY((is_substitution_failure<vi8<char>, long>));
+	VERIFY((is_substitution_failure<vi8<char>, ulong>));
+	VERIFY((is_substitution_failure<vi8<char>, ullong>));
+	VERIFY((is_substitution_failure<vi8<char>, float>));
+
+	// conversion between any char types must fail because the dst type's
+	// integer conversion rank isn't greater (as required by 9.6.4p4.3)
+	VERIFY((is_substitution_failure<vi8<char>, vi8<schar>>));
+	VERIFY((is_substitution_failure<vi8<char>, vi8<uchar>>));
+      }
+    else if constexpr (std::is_same_v<V, vschar>)
+      {
+	binary_op_return_type<vi8<schar>, schar, vi8<schar>>();
+	binary_op_return_type<vi8<schar>, int, vi8<schar>>();
+	binary_op_return_type<vi8<schar>, vi8<schar>, vi8<schar>>();
+
+	if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+	  {
+	    binary_op_return_type<vi8<short>, vi8<schar>>();
+	    binary_op_return_type<vi8<int>, vi8<schar>>();
+	    binary_op_return_type<vi8<long>, vi8<schar>>();
+	    binary_op_return_type<vi8<llong>, vi8<schar>>();
+	    binary_op_return_type<vi8<float>, vi8<schar>>();
+	    binary_op_return_type<vi8<double>, vi8<schar>>();
+	  }
+
+	VERIFY((is_substitution_failure<vi8<schar>, llong>));
+	VERIFY((is_substitution_failure<vi8<schar>, double>));
+	VERIFY((is_substitution_failure<vschar, vuchar>));
+	VERIFY((is_substitution_failure<vschar, uchar>));
+	VERIFY((is_substitution_failure<vschar, short>));
+	VERIFY((is_substitution_failure<vschar, ushort>));
+	VERIFY((is_substitution_failure<vschar, uint>));
+	VERIFY((is_substitution_failure<vschar, long>));
+	VERIFY((is_substitution_failure<vschar, ulong>));
+	VERIFY((is_substitution_failure<vschar, llong>));
+	VERIFY((is_substitution_failure<vschar, ullong>));
+	VERIFY((is_substitution_failure<vschar, float>));
+	VERIFY((is_substitution_failure<vschar, double>));
+	VERIFY((is_substitution_failure<vschar, vi8<schar>>));
+	VERIFY((is_substitution_failure<vschar, vi8<uchar>>));
+	VERIFY((is_substitution_failure<vschar, vi8<short>>));
+	VERIFY((is_substitution_failure<vschar, vi8<ushort>>));
+	VERIFY((is_substitution_failure<vschar, vi8<int>>));
+	VERIFY((is_substitution_failure<vschar, vi8<uint>>));
+	VERIFY((is_substitution_failure<vschar, vi8<long>>));
+	VERIFY((is_substitution_failure<vschar, vi8<ulong>>));
+	VERIFY((is_substitution_failure<vschar, vi8<llong>>));
+	VERIFY((is_substitution_failure<vschar, vi8<ullong>>));
+	VERIFY((is_substitution_failure<vschar, vi8<float>>));
+	VERIFY((is_substitution_failure<vschar, vi8<double>>));
+	VERIFY((is_substitution_failure<vi8<schar>, vschar>));
+	VERIFY((is_substitution_failure<vi8<schar>, vuchar>));
+	VERIFY((is_substitution_failure<vi8<schar>, uchar>));
+	VERIFY((is_substitution_failure<vi8<schar>, short>));
+	VERIFY((is_substitution_failure<vi8<schar>, ushort>));
+	VERIFY((is_substitution_failure<vi8<schar>, uint>));
+	VERIFY((is_substitution_failure<vi8<schar>, long>));
+	VERIFY((is_substitution_failure<vi8<schar>, ulong>));
+	VERIFY((is_substitution_failure<vi8<schar>, ullong>));
+	VERIFY((is_substitution_failure<vi8<schar>, float>));
+	VERIFY((is_substitution_failure<vi8<schar>, vi8<uchar>>));
+	VERIFY((is_substitution_failure<vi8<schar>, vi8<ushort>>));
+	VERIFY((is_substitution_failure<vi8<schar>, vi8<uint>>));
+	VERIFY((is_substitution_failure<vi8<schar>, vi8<ulong>>));
+	VERIFY((is_substitution_failure<vi8<schar>, vi8<ullong>>));
+      }
+    else if constexpr (std::is_same_v<V, vuchar>)
+      {
+	VERIFY((is_substitution_failure<vi8<uchar>, llong>));
+
+	binary_op_return_type<vuchar, uint, vuchar>();
+	binary_op_return_type<vi8<uchar>, uchar, vi8<uchar>>();
+	binary_op_return_type<vi8<uchar>, int, vi8<uchar>>();
+	binary_op_return_type<vi8<uchar>, uint, vi8<uchar>>();
+	binary_op_return_type<vi8<uchar>, vi8<uchar>, vi8<uchar>>();
+
+	if constexpr (vi8<schar>::size() <= simd_abi::max_fixed_size<short>)
+	  {
+	    binary_op_return_type<vi8<short>, vi8<uchar>>();
+	    binary_op_return_type<vi8<ushort>, vi8<uchar>>();
+	    binary_op_return_type<vi8<int>, vi8<uchar>>();
+	    binary_op_return_type<vi8<uint>, vi8<uchar>>();
+	    binary_op_return_type<vi8<long>, vi8<uchar>>();
+	    binary_op_return_type<vi8<ulong>, vi8<uchar>>();
+	    binary_op_return_type<vi8<llong>, vi8<uchar>>();
+	    binary_op_return_type<vi8<ullong>, vi8<uchar>>();
+	    binary_op_return_type<vi8<float>, vi8<uchar>>();
+	    binary_op_return_type<vi8<double>, vi8<uchar>>();
+	  }
+
+	VERIFY((is_substitution_failure<vi8<uchar>, ullong>));
+	VERIFY((is_substitution_failure<vi8<uchar>, double>));
+	VERIFY((is_substitution_failure<vuchar, schar>));
+	VERIFY((is_substitution_failure<vuchar, vschar>));
+	VERIFY((is_substitution_failure<vuchar, short>));
+	VERIFY((is_substitution_failure<vuchar, ushort>));
+	VERIFY((is_substitution_failure<vuchar, long>));
+	VERIFY((is_substitution_failure<vuchar, ulong>));
+	VERIFY((is_substitution_failure<vuchar, llong>));
+	VERIFY((is_substitution_failure<vuchar, ullong>));
+	VERIFY((is_substitution_failure<vuchar, float>));
+	VERIFY((is_substitution_failure<vuchar, double>));
+	VERIFY((is_substitution_failure<vuchar, vi8<schar>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<uchar>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<short>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<ushort>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<int>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<uint>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<long>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<ulong>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<llong>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<ullong>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<float>>));
+	VERIFY((is_substitution_failure<vuchar, vi8<double>>));
+	VERIFY((is_substitution_failure<vi8<uchar>, schar>));
+	VERIFY((is_substitution_failure<vi8<uchar>, vschar>));
+	VERIFY((is_substitution_failure<vi8<uchar>, vuchar>));
+	VERIFY((is_substitution_failure<vi8<uchar>, short>));
+	VERIFY((is_substitution_failure<vi8<uchar>, ushort>));
+	VERIFY((is_substitution_failure<vi8<uchar>, long>));
+	VERIFY((is_substitution_failure<vi8<uchar>, ulong>));
+	VERIFY((is_substitution_failure<vi8<uchar>, float>));
+	VERIFY((is_substitution_failure<vi8<uchar>, vi8<schar>>));
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc
new file mode 100644
index 00000000000..cee696cc69b
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/operators.cc
@@ -0,0 +1,297 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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..6f4ba40133f
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/reductions.cc
@@ -0,0 +1,97 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+#include <random>
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    COMPARE(reduce(V(1)), T(V::size()));
+    {
+      V x = 1;
+      COMPARE(reduce(x, std::multiplies<>()), T(1));
+      x[0] = 2;
+      COMPARE(reduce(x, std::multiplies<>()), T(2));
+      if constexpr (V::size() > 1)
+	{
+	  x[V::size() - 1] = 3;
+	  COMPARE(reduce(x, std::multiplies<>()), T(6));
+	}
+    }
+    COMPARE(reduce(V([](int i) { return i & 1; })), T(V::size() / 2));
+    COMPARE(reduce(V([](int i) { return i % 3; })),
+	    T(3 * (V::size() / 3)   // 0+1+2 for every complete 3 elements in V
+		+ (V::size() % 3) / 2 // 0->0, 1->0, 2->1 adjustment
+	     ));
+    if ((1 + V::size()) * V::size() / 2 <= std::__finite_max_v<T>)
+      {
+	COMPARE(reduce(V([](int i) { return i + 1; })),
+		T((1 + V::size()) * V::size() / 2));
+      }
+
+    {
+      const V y = 2;
+      COMPARE(reduce(y), T(2 * V::size()));
+      COMPARE(reduce(where(y > 2, y)), T(0));
+      COMPARE(reduce(where(y == 2, y)), T(2 * V::size()));
+    }
+
+    {
+      const V z([](T i) { return i + 1; });
+      COMPARE(std::experimental::reduce(z,
+					[](auto a, auto b) {
+					  using std::min;
+					  return min(a, b);
+					}),
+	      T(1))
+	<< "z: " << z;
+      COMPARE(std::experimental::reduce(z,
+					[](auto a, auto b) {
+					  using std::max;
+					  return max(a, b);
+					}),
+	      T(V::size()))
+	<< "z: " << z;
+      COMPARE(std::experimental::reduce(where(z > 1, z), 117,
+					[](auto a, auto b) {
+					  using std::min;
+					  return min(a, b);
+					}),
+	      T(V::size() == 1 ? 117 : 2))
+	<< "z: " << z;
+    }
+
+    test_values<V>({}, {1000}, [](V x) {
+      // avoid over-/underflow on signed integers:
+      if constexpr (std::is_signed_v<T> && std::is_integral_v<T>)
+	x /= int(V::size());
+      // The error in the following could be huge if catastrophic
+      // cancellation occurs. (e.g. `a-a+b+b` vs. `a+b+b-a`).
+      // Avoid catastrophic cancellation for floating point:
+      if constexpr (std::is_floating_point_v<T>)
+	x = abs(x);
+      T acc = x[0];
+      for (size_t i = 1; i < V::size(); ++i)
+	acc += x[i];
+      ULP_COMPARE(reduce(x), acc, V::size() / 2).on_failure("x = ", x);
+    });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc
new file mode 100644
index 00000000000..bdbacc6ef8e
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/remqo.cc
@@ -0,0 +1,70 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(0);
+    vir::test::setFuzzyness<double>(0);
+
+    using T = typename V::value_type;
+    test_values_2arg<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>,
+	std::__denorm_min_v<T>, std::__norm_min_v<T> / 3, -0.,
+#endif
+	+0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+      {10000}, [](V a, V b) {
+
+#ifndef __STDC_IEC_559__
+	// without __STDC_IEC_559__, remquo(a, 0) is unspecified
+	where(b == 0, b) = 1;
+#endif
+	using IV = std::experimental::fixed_size_simd<int, V::size()>;
+	IV quo = {};
+	const V totest = remquo(a, b, &quo);
+	auto&& expected
+	  = [&](const auto& v, const auto& w) -> std::pair<const V, const IV> {
+	    std::pair<V, IV> tmp = {};
+	    using std::remquo;
+	    for (std::size_t i = 0; i < V::size(); ++i)
+	      {
+		int tmp2;
+		tmp.first[i] = remquo(v[i], w[i], &tmp2);
+		tmp.second[i] = tmp2;
+	      }
+	    return tmp;
+	  };
+	const auto expect1 = expected(a, b);
+	COMPARE(isnan(totest), isnan(expect1.first))
+	  << "remquo(" << a << ", " << b << ", quo) = " << totest
+	  << " != " << expect1.first;
+	const V clean_a = iif(isnan(totest), 0, a);
+	const V clean_b = iif(isnan(totest), 1, b);
+	const auto expect2 = expected(clean_a, clean_b);
+	COMPARE(remquo(clean_a, clean_b, &quo), expect2.first)
+	  << "\nclean_a/b = " << clean_a << ", " << clean_b;
+	COMPARE(quo, expect2.second);
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc
new file mode 100644
index 00000000000..657646c0ac5
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/simd.cc
@@ -0,0 +1,46 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+
+    // V must store V::size() values of type T giving us the lower bound on the
+    // sizeof
+    VERIFY(sizeof(V) >= sizeof(T) * V::size());
+
+    // For fixed_size, V should not pad more than to the next-power-of-2 of
+    // sizeof(T) * V::size() (for ABI stability of V), giving us the upper bound
+    // on the sizeof. For non-fixed_size we give the implementation a bit more
+    // slack to trade space vs. efficiency.
+    auto n = sizeof(T) * V::size();
+    if (n & (n - 1))
+      {
+	n = ((n << 1) & ~n) & ~((n >> 1) | (n >> 3));
+	while (n & (n - 1))
+	  n &= n - 1;
+      }
+    if constexpr (
+      !std::is_same_v<typename V::abi_type,
+		      std::experimental::simd_abi::fixed_size<V::size()>>)
+      n *= 2;
+    VERIFY(sizeof(V) <= n) << "\nsizeof(V): " << sizeof(V) << "\nn: " << n;
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc
new file mode 100644
index 00000000000..acef488e214
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/sincos.cc
@@ -0,0 +1,44 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/mathreference.h"
+#include "bits/simd_view.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using std::cos;
+    using std::sin;
+    using T = typename V::value_type;
+
+    vir::test::setFuzzyness<float>(2);
+    vir::test::setFuzzyness<double>(1);
+
+    const auto& testdata = referenceData<function::sincos, T>();
+    std::experimental::experimental::simd_view<V>(testdata).for_each(
+      [&](const V input, const V expected_sin, const V expected_cos) {
+	FUZZY_COMPARE(sin(input), expected_sin) << " input = " << input;
+	FUZZY_COMPARE(sin(-input), -expected_sin) << " input = " << input;
+	FUZZY_COMPARE(cos(input), expected_cos) << " input = " << input;
+	FUZZY_COMPARE(cos(-input), expected_cos) << " input = " << input;
+      });
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc
new file mode 100644
index 00000000000..3a79a1f8e3d
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/split_concat.cc
@@ -0,0 +1,183 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/conversions.h"
+
+using std::experimental::simd_cast;
+
+template <typename V, bool ConstProp, typename F>
+  auto
+  gen(const F& fun)
+  {
+    if constexpr (ConstProp)
+      return V(fun);
+    else
+      return make_value_unknown(V(fun));
+  }
+
+template <typename V, bool ConstProp>
+  void
+  split_concat()
+  {
+    using T = typename V::value_type;
+    if constexpr (V::size() * 3
+		    <= std::experimental::simd_abi::max_fixed_size<T>)
+      {
+	V a(0), b(1), c(2);
+	auto x = concat(a, b, c);
+	COMPARE(x.size(), a.size() * 3);
+	std::size_t i = 0;
+	for (; i < a.size(); ++i)
+	  {
+	    COMPARE(x[i], T(0));
+	  }
+	for (; i < 2 * a.size(); ++i)
+	  {
+	    COMPARE(x[i], T(1));
+	  }
+	for (; i < 3 * a.size(); ++i)
+	  {
+	    COMPARE(x[i], T(2));
+	  }
+      }
+
+    if constexpr (V::size() >= 4)
+      {
+	const V a = gen<V, ConstProp>([](auto i) -> T { return i; });
+	constexpr auto N0 = V::size() / 4u;
+	constexpr auto N1 = V::size() - 2 * N0;
+	using V0 = std::experimental::simd<
+		     T, std::experimental::simd_abi::deduce_t<T, N0>>;
+	using V1 = std::experimental::simd<
+		     T, std::experimental::simd_abi::deduce_t<T, N1>>;
+	{
+	  auto x = std::experimental::split<N0, N0, N1>(a);
+	  COMPARE(std::tuple_size<decltype(x)>::value, 3u);
+	  COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; }));
+	  COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N0; }));
+	  COMPARE(std::get<2>(x), V1([](auto i) -> T { return i + 2 * N0; }));
+	  auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x));
+	  // a and b may have different types if a was fixed_size<N> such that
+	  // another ABI tag exists with equal N, then b will have the
+	  // non-fixed-size ABI tag.
+	  COMPARE(a.size(), b.size());
+	  COMPARE(
+	    b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); }));
+	}
+	{
+	  auto x = std::experimental::split<N0, N1, N0>(a);
+	  COMPARE(std::tuple_size<decltype(x)>::value, 3u);
+	  COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; }));
+	  COMPARE(std::get<1>(x), V1([](auto i) -> T { return i + N0; }));
+	  COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; }));
+	  auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x));
+	  // a and b may have different types if a was fixed_size<N> such that
+	  // another ABI tag exists with equal N, then b will have the
+	  // non-fixed-size ABI tag.
+	  COMPARE(a.size(), b.size());
+	  COMPARE(
+	    b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); }));
+	}
+	{
+	  auto x = std::experimental::split<N1, N0, N0>(a);
+	  COMPARE(std::tuple_size<decltype(x)>::value, 3u);
+	  COMPARE(std::get<0>(x), V1([](auto i) -> T { return i; }));
+	  COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N1; }));
+	  COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; }));
+	  auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x));
+	  // a and b may have different types if a was fixed_size<N> such that
+	  // another ABI tag exists with equal N, then b will have the
+	  // non-fixed-size ABI tag.
+	  COMPARE(a.size(), b.size());
+	  COMPARE(
+	    b, decltype(b)([](auto i) -> T { return (N1 + i) % V::size(); }));
+	}
+      }
+
+    if constexpr (V::size() % 3 == 0)
+      {
+	const V a = gen<V, ConstProp>([](auto i) -> T { return i; });
+	constexpr auto N0 = V::size() / 3;
+	using V0 = std::experimental::simd<
+		     T, std::experimental::simd_abi::deduce_t<T, N0>>;
+	using V1 = std::experimental::simd<
+	  T, std::experimental::simd_abi::deduce_t<T, 2 * N0>>;
+	{
+	  auto [x, y, z] = std::experimental::split<N0, N0, N0>(a);
+	  COMPARE(x, V0([](auto i) -> T { return i; }));
+	  COMPARE(y, V0([](auto i) -> T { return i + N0; }));
+	  COMPARE(z, V0([](auto i) -> T { return i + N0 * 2; }));
+	  auto b = concat(x, y, z);
+	  COMPARE(a.size(), b.size());
+	  COMPARE(b, simd_cast<decltype(b)>(a));
+	  COMPARE(simd_cast<V>(b), a);
+	}
+	{
+	  auto [x, y] = std::experimental::split<N0, 2 * N0>(a);
+	  COMPARE(x, V0([](auto i) -> T { return i; }));
+	  COMPARE(y, V1([](auto i) -> T { return i + N0; }));
+	  auto b = concat(x, y);
+	  COMPARE(a.size(), b.size());
+	  COMPARE(b, simd_cast<decltype(b)>(a));
+	  COMPARE(simd_cast<V>(b), a);
+	}
+	{
+	  auto [x, y] = std::experimental::split<2 * N0, N0>(a);
+	  COMPARE(x, V1([](auto i) -> T { return i; }));
+	  COMPARE(y, V0([](auto i) -> T { return i + 2 * N0; }));
+	  auto b = concat(x, y);
+	  COMPARE(a.size(), b.size());
+	  COMPARE(b, simd_cast<decltype(b)>(a));
+	  COMPARE(simd_cast<V>(b), a);
+	}
+      }
+
+    if constexpr ((V::size() & 1) == 0)
+      {
+	using std::experimental::simd;
+	using std::experimental::simd_abi::deduce_t;
+	using V0 = simd<T, deduce_t<T, V::size()>>;
+	using V2 = simd<T, deduce_t<T, 2>>;
+	using V3 = simd<T, deduce_t<T, V::size() / 2>>;
+
+	const V a = gen<V, ConstProp>([](auto i) -> T { return i; });
+
+	std::array<V2, V::size() / 2> v2s = std::experimental::split<V2>(a);
+	int offset = 0;
+	for (V2 test : v2s)
+	  {
+	    COMPARE(test, V2([&](auto i) -> T { return i + offset; }));
+	    offset += 2;
+	  }
+	COMPARE(concat(v2s), simd_cast<V0>(a));
+
+	std::array<V3, 2> v3s = std::experimental::split<V3>(a);
+	COMPARE(v3s[0], V3([](auto i) -> T { return i; }));
+	COMPARE(v3s[1], V3([](auto i) -> T { return i + V3::size(); }));
+	COMPARE(concat(v3s), simd_cast<V0>(a));
+      }
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    split_concat<V, true>();
+    split_concat<V, false>();
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc
new file mode 100644
index 00000000000..8b61635c2a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/splits.cc
@@ -0,0 +1,38 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    using namespace std::experimental::parallelism_v2;
+    using T = typename V::value_type;
+    if constexpr (V::size() / simd_size_v<T> * simd_size_v<T> == V::size())
+      {
+	M k(true);
+	VERIFY(all_of(k)) << k;
+	const auto parts = split<simd_mask<T>>(k);
+	for (auto k2 : parts)
+	  {
+	    VERIFY(all_of(k2)) << k2;
+	    COMPARE(typeid(k2), typeid(simd_mask<T>));
+	  }
+      }
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc
new file mode 100644
index 00000000000..24730f1856c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/trigonometric.cc
@@ -0,0 +1,41 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/metahelpers.h"
+#include "bits/test_values.h"
+
+template <typename V>
+  void
+  test()
+  {
+    vir::test::setFuzzyness<float>(1);
+    vir::test::setFuzzyness<double>(1);
+
+    using T = typename V::value_type;
+    test_values<V>(
+      {
+#ifdef __STDC_IEC_559__
+	std::__quiet_NaN_v<T>, std::__infinity_v<T>, -std::__infinity_v<T>, -0.,
+	std::__denorm_min_v<T>, std::__norm_min_v<T> / 3,
+#endif
+	+0., std::__norm_min_v<T>, std::__finite_max_v<T>},
+      {10000}, MAKE_TESTER(acos), MAKE_TESTER(tan), MAKE_TESTER(acosh),
+      MAKE_TESTER(asinh), MAKE_TESTER(atanh), MAKE_TESTER(cosh),
+      MAKE_TESTER(sinh), MAKE_TESTER(tanh));
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc
new file mode 100644
index 00000000000..e516926ae1d
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/trunc_ceil_floor.cc
@@ -0,0 +1,109 @@ 
+// test only floattypes
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/test_values.h"
+#include "bits/verify.h"
+
+template <typename V>
+  void
+  test()
+  {
+    using T = typename V::value_type;
+    constexpr T inf = std::__infinity_v<T>;
+    constexpr T denorm_min = std::__denorm_min_v<T>;
+    constexpr T norm_min = std::__norm_min_v<T>;
+    constexpr T max = std::__finite_max_v<T>;
+    constexpr T min = std::__finite_min_v<T>;
+    test_values<V>(
+      {2.1,
+       2.0,
+       2.9,
+       2.5,
+       2.499,
+       1.5,
+       1.499,
+       1.99,
+       0.99,
+       0.5,
+       0.499,
+       0.,
+       -2.1,
+       -2.0,
+       -2.9,
+       -2.5,
+       -2.499,
+       -1.5,
+       -1.499,
+       -1.99,
+       -0.99,
+       -0.5,
+       -0.499,
+       3 << 21,
+       3 << 22,
+       3 << 23,
+       -(3 << 21),
+       -(3 << 22),
+       -(3 << 23),
+#ifdef __STDC_IEC_559__
+       -0.,
+       inf,
+       -inf,
+       denorm_min,
+       norm_min * 0.9,
+       -denorm_min,
+       -norm_min * 0.9,
+#endif
+       max,
+       norm_min,
+       min,
+       -norm_min
+      },
+      [](const V input) {
+	const V expected([&](auto i) { return std::trunc(input[i]); });
+	COMPARE(trunc(input), expected) << input;
+      },
+      [](const V input) {
+	const V expected([&](auto i) { return std::ceil(input[i]); });
+	COMPARE(ceil(input), expected) << input;
+      },
+      [](const V input) {
+	const V expected([&](auto i) { return std::floor(input[i]); });
+	COMPARE(floor(input), expected) << input;
+      });
+
+#ifdef __STDC_IEC_559__
+    test_values<V>(
+      {
+#ifdef __SUPPORT_SNAN__
+	std::__signaling_NaN_v<T>,
+#endif
+	std::__quiet_NaN_v<T>},
+      [](const V input) {
+	const V expected([&](auto i) { return std::trunc(input[i]); });
+	COMPARE(isnan(trunc(input)), isnan(expected)) << input;
+      },
+      [](const V input) {
+	const V expected([&](auto i) { return std::ceil(input[i]); });
+	COMPARE(isnan(ceil(input)), isnan(expected)) << input;
+      },
+      [](const V input) {
+	const V expected([&](auto i) { return std::floor(input[i]); });
+	COMPARE(isnan(floor(input)), isnan(expected)) << input;
+      });
+#endif
+  }
diff --git a/libstdc++-v3/testsuite/experimental/simd/tests/where.cc b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc
new file mode 100644
index 00000000000..5e73a3b1989
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/tests/where.cc
@@ -0,0 +1,136 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "bits/verify.h"
+#include "bits/make_vec.h"
+#include "bits/metahelpers.h"
+
+template <class V>
+  struct Convertible
+  {
+    operator V() const { return V(4); }
+  };
+
+template <class M, class T>
+  constexpr bool
+  where_is_ill_formed_impl(M, const T&, float)
+  {
+    return true;
+  }
+
+template <class M, class T>
+  constexpr auto
+  where_is_ill_formed_impl(M m, const T& v, int)
+    -> std::conditional_t<true, bool, decltype(std::experimental::where(m, v))>
+  {
+    return false;
+  }
+
+template <class M, class T>
+  constexpr bool
+  where_is_ill_formed(M m, const T& v)
+  {
+    return where_is_ill_formed_impl(m, v, int());
+  }
+
+template <typename T>
+  void
+  where_fundamental()
+  {
+    using std::experimental::where;
+    T x = T();
+    where(true, x) = x + 1;
+    COMPARE(x, T(1));
+    where(false, x) = x - 1;
+    COMPARE(x, T(1));
+    where(true, x) += T(1);
+    COMPARE(x, T(2));
+  }
+
+template <typename V>
+  void
+  test()
+  {
+    using M = typename V::mask_type;
+    using T = typename V::value_type;
+    where_fundamental<T>();
+    VERIFY(!(sfinae_is_callable<V>(
+	       [](auto x) -> decltype(where(true, x))* { return nullptr; })));
+
+    const V indexes([](int i) { return i + 1; });
+    const M alternating_mask = make_mask<M>({true, false});
+    V x = 0;
+    where(alternating_mask, x) = indexes;
+    COMPARE(alternating_mask, x == indexes);
+
+    where(!alternating_mask, x) = T(2);
+    COMPARE(!alternating_mask, x == T(2)) << x;
+
+    where(!alternating_mask, x) = Convertible<V>();
+    COMPARE(!alternating_mask, x == T(4));
+
+    x = 0;
+    COMPARE(x, T(0));
+    where(alternating_mask, x) += indexes;
+    COMPARE(alternating_mask, x == indexes);
+
+    x = 10;
+    COMPARE(x, T(10));
+    where(!alternating_mask, x) += T(1);
+    COMPARE(!alternating_mask, x == T(11));
+    where(alternating_mask, x) -= Convertible<V>();
+    COMPARE(alternating_mask, x == T(6));
+    constexpr bool fast_math =
+#ifdef __FAST_MATH__
+      true;
+#else
+      false;
+#endif
+    if constexpr (fast_math && std::is_floating_point_v<T>)
+      where(alternating_mask, x) *= T(.5);
+    else
+    where(alternating_mask, x) /= T(2);
+    COMPARE(alternating_mask, x == T(3)) << "\nx = " << x;
+    where(alternating_mask, x) *= T(3);
+    COMPARE(alternating_mask, x == T(9));
+    COMPARE(!alternating_mask, x == T(11));
+
+    x = 10;
+    where(alternating_mask, x)++;
+    COMPARE(alternating_mask, x == T(11));
+    ++where(alternating_mask, x);
+    COMPARE(alternating_mask, x == T(12));
+    where(alternating_mask, x)--;
+    COMPARE(alternating_mask, x == T(11));
+    --where(alternating_mask, x);
+    --where(alternating_mask, x);
+    COMPARE(alternating_mask, x == T(9));
+    COMPARE(alternating_mask, -where(alternating_mask, x) == T(-T(9)));
+
+    const auto y = x;
+    VERIFY(where_is_ill_formed(true, y));
+    VERIFY(where_is_ill_formed(true, x));
+    VERIFY(where_is_ill_formed(true, V(x)));
+
+    M test = alternating_mask;
+    where(alternating_mask, test) = M(true);
+    COMPARE(test, alternating_mask);
+    where(alternating_mask, test) = M(false);
+    COMPARE(test, M(false));
+    where(alternating_mask, test) = M(true);
+    COMPARE(test, alternating_mask);
+  }