libstdc++: Add simd testsuite

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

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

To use a simulator, the CHECK_SIMD_CONFIG variable needs to point to a
shell script which calls `define_target <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.
This commit is contained in:
Matthias Kretz 2021-01-21 11:50:32 +00:00 committed by Jonathan Wakely
parent 2bcceb6fc5
commit 02e32295b2
46 changed files with 6746 additions and 5 deletions

75
libstdc++-v3/scripts/check_simd Executable file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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"

View File

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

View File

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

View File

@ -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]; }
};

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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_

View File

@ -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_)

View File

@ -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

View File

@ -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_

View File

@ -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>()));
}

View File

@ -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>();
}

View File

@ -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
}

View File

@ -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
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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>();
}

View File

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

View File

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

View File

@ -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>();
}

View File

@ -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()>>();
}

View File

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

View File

@ -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>>();
}

View File

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

View File

@ -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 {};
}));
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

@ -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>();
}

View File

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

View File

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

View File

@ -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
}

View File

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