From 0c4105171b67dca3d65237b8f83db708f8a95203 Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Tue, 21 May 2024 21:46:47 +0200 Subject: [PATCH] D3287R0 (exploration of simd namespaces) draft ready for review ChangeLog: * P3287_exploration_of_namespaces_for_simd/Makefile: New file. * P3287_exploration_of_namespaces_for_simd/alt1.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt2.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt3.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt4.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt5.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt6.tex: New file. * P3287_exploration_of_namespaces_for_simd/alt7.tex: New file. * P3287_exploration_of_namespaces_for_simd/changelog.tex: New file. * P3287_exploration_of_namespaces_for_simd/main.tex: New file. * P3287_exploration_of_namespaces_for_simd/strawpolls.tex: New file. * listingscpp.sty: * wg21.sty: --- .../Makefile | 133 +++++++++ .../alt1.tex | 131 +++++++++ .../alt2.tex | 118 ++++++++ .../alt3.tex | 129 +++++++++ .../alt4.tex | 67 +++++ .../alt5.tex | 246 +++++++++++++++++ .../alt6.tex | 155 +++++++++++ .../alt7.tex | 183 ++++++++++++ .../changelog.tex | 5 + .../main.tex | 260 ++++++++++++++++++ .../strawpolls.tex | 2 + listingscpp.sty | 13 +- wg21.sty | 40 +-- 13 files changed, 1462 insertions(+), 20 deletions(-) create mode 100644 P3287_exploration_of_namespaces_for_simd/Makefile create mode 100644 P3287_exploration_of_namespaces_for_simd/alt1.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt2.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt3.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt4.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt5.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt6.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/alt7.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/changelog.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/main.tex create mode 100644 P3287_exploration_of_namespaces_for_simd/strawpolls.tex diff --git a/P3287_exploration_of_namespaces_for_simd/Makefile b/P3287_exploration_of_namespaces_for_simd/Makefile new file mode 100644 index 0000000..815f844 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/Makefile @@ -0,0 +1,133 @@ +NAME := $(shell grep 'newcommand.wgDocumentNumber' main.tex|cut -f2 -d'{'|cut -f1 -d'}') +DRAFT := $(NAME)_draft +TEXINPUTS := ..:.: +PDFLATEX := TEXINPUTS=$(TEXINPUTS) flock . lualatex --shell-escape --halt-on-error --file-line-error --interaction nonstopmode +BIBER := biber --input-directory .. --output-directory . +MAKEINDEX := makeindex +SHELL := /bin/bash +EXTRA_DEPS := $(wildcard *.sty ../*.sty) ._dummy.tex +CREATEMD5 := md5sum `find . -regex '.*\.\(aux\|bbl\|toc\|tex\|ind\)'` > ._aux-md5sums +CHECKMD5 := md5sum --quiet -c ._aux-md5sums +UPLOADNAME := D$(shell echo $(NAME)|cut -c2-5).pdf + +all: final + +._dummy.tex: + touch $@ + +help: + @echo "all" + @echo "devel" + @echo "draft-loop" + @echo "final-loop" + @echo "final-figure-loop" + @echo "draft" + @echo "final" + @echo "clean" + @echo "autocommit" + +TEX_INPUTS := $(shell egrep '^[^%]*\\in(put|clude){.*?}' main.tex|sed 's@^.*{\(.*\)}.*$$@\1.tex@') +TEX_INPUTS2 := $(shell test -n "$(TEX_INPUTS)" && egrep '^[^%]*\\in(put|clude){.*?}' $(TEX_INPUTS) ._dummy.tex|sed -e 's@^.*{\([^.]*\)}.*$$@\1.tex@' -e 's@^.*{\(.*\)}.*$$@\1@') $(TEX_INPUTS) +TEX_INPUTS := $(shell test -n "$(TEX_INPUTS2)" && egrep '^[^%]*\\in(put|clude){.*?}' $(TEX_INPUTS2) ._dummy.tex|sed -e 's@^.*{\([^.]*\)}.*$$@\1.tex@' -e 's@^.*{\(.*\)}.*$$@\1@') $(TEX_INPUTS2) $(TEX_INPUTS) main.tex +TEX_LISTINGS := $(shell test -n "$(TEX_INPUTS)" && awk -F '{|}' -- '/lstinputlisting\[[^\]]*$$/ { getline; while($$0 !~ /\] *{.*\..*}$$/) getline; sub(/^.*\]/, ""); print } /lstinputlisting\[.*\] *{.*}/ { print }' $(TEX_INPUTS) |sed 's=.*\(\[[^]]*\]\)\?{\([^}]*\)}.*=\2='| sort -u) +TEX_PLOTDATA := $(shell grep '\\addplot.* file' $(TEX_INPUTS)|sed 's=^.*\\addplot.* file *{\(.*\)}.*$$=\1=') +GRAPHICS := $(shell grep 'includegraphics' main.tex $(TEX_INPUTS)|grep -v newcommand|sed -e 's=.*\\includegraphics[^{]*{\([^}]*\)}.*=\1=' |sort -u|while read f; do for d in $(subst :, ,$(TEXINPUTS)); do test -f $$d/$$f && echo $$d/$$f && break; done; done) +ALL_DEPS := $(TEX_INPUTS) $(TEX_LISTINGS) $(TEX_PLOTDATA) $(GRAPHICS) $(EXTRA_DEPS) + +devel: final-loop + +draft: $(DRAFT).pdf +final: $(NAME).pdf +mobile: $(NAME)_mobile.pdf + +upload: $(NAME).pdf + @echo -n "Uploading $< ." + @while ! timeout 120s scp -B $< lxpool.gsi.de:web-docs/$(UPLOADNAME); do echo -n .; done + @echo . + +loop-internal: + @screenTitle() { case "$$TERM" in screen*|tmux*) printf '\ek%s\e\\' "$$*";; *) printf '\e]1;%s:q\a' "$$*";; esac }; \ + while true; do \ + while true; do \ + screenTitle 'LaTeX waiting: $(loopinternaltarget)'; \ + if ! $(MAKE) -q $(loopinternaltarget).pdf>/dev/null; then \ + screenTitle 'LaTeX build: $(loopinternaltarget)'; \ + ls -lt $(ALL_DEPS) | head -n1 > ._stamp; \ + nice ionice -c idle $(MAKE) $(loopinternaltarget).pdf || break; \ + fi; \ + sleep 1s; \ + done; \ + screenTitle 'failed'; \ + kdialog --passivepopup "LaTeX ($(NAME)) failed" 1; \ + echo -e '\a'; \ + ls -lt $(ALL_DEPS) $(MORE_DEPS) | head -n1 > ._stamp.new; \ + while diff -q ._stamp ._stamp.new; do \ + sleep 1s; \ + ls -lt $(ALL_DEPS) $(MORE_DEPS) | head -n1 > ._stamp.new; \ + done; \ + done + +draft-loop: + $(MAKE) loopinternaltarget=$(DRAFT) MORE_DEPS=../draft.tex loop-internal + +final-loop: + $(MAKE) loopinternaltarget=$(NAME) MORE_DEPS=../final.tex loop-internal + +%-loop: + $(MAKE) loopinternaltarget=$(NAME)_$* MORE_DEPS=../$*.tex loop-internal + +final-figure%-loop: + @while true; do $(MAKE) -q final-figure$*.pdf || $(MAKE) final-figure$*.pdf && sleep 1s; done + +clean: + rm -f $(NAME).pdf $(DRAFT).pdf *.aux *.bbl *.blg *.brf *.lof *.log *.lol *.lot *.out *.toc */*.aux *.auxlock ._aux-md5sums *.bcf *.run.xml ._stamp ._stamp.new + +ALL_DEPS=$(TEX_INPUTS) $(TEX_LISTINGS) $(EXTRA_DEPS) $(TEX_PLOTDATA) + +$(DRAFT).pdf: ../draft.tex $(ALL_DEPS) + $(PDFLATEX) ../draft + @test -s draft.pdf && mv draft.pdf $@ + $(BIBER) draft || true + +$(NAME).pdf: ../final.tex $(ALL_DEPS) + @$(CREATEMD5) + $(PDFLATEX) ../final + @test -s final.pdf && mv final.pdf $@ + $(BIBER) final || true + @while ! $(CHECKMD5); do \ + $(CREATEMD5); \ + $(PDFLATEX) ../final; \ + test -s final.pdf && mv final.pdf $@; \ + done + test "$(USER)" = "mkretz" && timeout 20s scp -B $@ lxpool.gsi.de:web-docs/$(UPLOADNAME) & + +$(NAME)_%.pdf: ../%.tex $(ALL_DEPS) + @$(CREATEMD5) + $(PDFLATEX) ../$* + @test -s $*.pdf && mv $*.pdf $@ + test -f $*.bcf && $(BIBER) $* || true + test -f $*.ind && $(MAKEINDEX) $* || true + while ! $(CHECKMD5); do \ + $(CREATEMD5); \ + $(PDFLATEX) ../$*; \ + test -s $*.pdf && mv $*.pdf $@; \ + test -f $*.ind && $(MAKEINDEX) $*; \ + done + +final-figure%.pdf: final.tex $(ALL_DEPS) + $(PDFLATEX) --halt-on-error --interaction=nonstopmode --jobname "final-figure$*" "\def\tikzexternalrealjob{final}\input{final}" + +autocommit: + @screenTitle() { echo $$TERM|grep -q screen && printf '\ek%s\e\\' "$$*"; }; \ + screenTitle 'autocommit' \ + while true; do \ + git commit -am "auto: `git status --porcelain|grep -v '^??'|cut -c4-|paste -s -d' '`" && \ + screenTitle 'committed' && \ + git push && \ + screenTitle 'committed & pushed'; \ + sleep 5s; \ + screenTitle 'autocommit'; \ + sleep 55s; \ + done + +.PHONY: clean diff --git a/P3287_exploration_of_namespaces_for_simd/alt1.tex b/P3287_exploration_of_namespaces_for_simd/alt1.tex new file mode 100644 index 0000000..87d50cf --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt1.tex @@ -0,0 +1,131 @@ +\subsection{Alternative 1: every function is a non-member with \code{simd} prefix} + +\medskip\begin{lstlisting}[style=Vc] +template + V + simd_generate(G&& gen); + +template + conditional_t, simd>, V> + simd_copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + simd_gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + simd_permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + simd_select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + basic_simd + simd_exp(const basic_simd& x); + +template + basic_simd + simd_min(const basic_simd& x, const basic_simd& y); + +template + bool + simd_all_of(const basic_simd_mask&); + +template + concept simd_integral = /*...*/; + +template + concept simd_generic_integral = integral or simd_integral; +\end{lstlisting} + +Usage example: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd vf, const std::vector& data) { + auto iota = std::simd_generate>([](int i) { return i; }); + auto chunk = std::simd_copy_from(data.begin()); + auto chunk_swapped = std::simd_gather_from(data, iota ^ 1); + auto chunk_swapped2 = std::simd_permute(chunk, [](int i) { return i ^ 1; }); + assert(std::simd_all_of(chunk_swapped == chunk_swapped2)); + + vf = std::simd_select(vf > 1.f, 1.f, vf); + vf = std::simd_exp(vf); + auto lo = std::simd_min(iota, chunk); +} +\end{lstlisting} + +There is little variation possible for the above code. +The most important variation is using unqualified calls, relying on ADL: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd vf, const std::vector& data) { + auto iota = std::simd_generate>([](int i) { return i; }); + auto chunk = std::simd_copy_from(data.begin()); + auto chunk_swapped = simd_gather_from(data, iota ^ 1); + auto chunk_swapped2 = simd_permute(chunk, [](int i) { return i ^ 1; }); + assert(simd_all_of(chunk_swapped == chunk_swapped2)); + + vf = simd_select(vf > 1.f, 1.f, vf); + vf = simd_exp(vf); + auto lo = simd_min(iota, chunk); +} +\end{lstlisting} + +For \simdgeneric programming a trivial example looks like this: +\medskip\begin{lstlisting}[style=Vc] +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T simd_only(T a, T b) { + return 2 * std::simd_min(a, b); +} + +template +T generic(T a, T b) { + if constexpr (std::simd_integral) + return 2 * std::simd_min(a, b); + else + return 2 * std::min(a, b); +} +\end{lstlisting} + +The ability to constrain a function like this actually resolves a missing +feature in the TS that I hit when working on using \stdx\code{simd} in the +core of the GNU Radio framework. +Obviously, the TS couldn't have proposed any concepts. +The ability to constrain a function with any of the three choices above had to +be solved with an ad-hoc solution in GNU Radio. + +However, looking at the implementation of the \code{generic} function above, +this can't be what we want. + +\begin{description} + \item[pros] + \begin{itemize} + \item Consistent. + \item[$\Rightarrow$] Users don't need to remember which functions don't + need a \code{simd} prefix. + + \item Consistent naming scheme for SIMD and \simdgeneric concepts. + \end{itemize} + + \item[cons] + \begin{itemize} + \item Verbose. + \item[$\Rightarrow$] There's a lot of “simd” spelled out in the code. + It is not adding information (IOW: it's noise) -- at least in this + code. + + \item \simdgeneric programming is barely possible (because it requires + too many constexpr-if branches). + \end{itemize} +\end{description} + +\myrating{unacceptable for lack of \simdgeneric programming; +too verbose without opt-out of the verbosity; +there must be a better alternative} diff --git a/P3287_exploration_of_namespaces_for_simd/alt2.tex b/P3287_exploration_of_namespaces_for_simd/alt2.tex new file mode 100644 index 0000000..126bf93 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt2.tex @@ -0,0 +1,118 @@ +\subsection{Alternative 2: every function is a non-member without \code{simd} prefix} + +\medskip\begin{lstlisting}[style=Vc] +template + V + generate(G&& gen); + +template + conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + basic_simd + exp(const basic_simd& x); + +template + basic_simd + min(const basic_simd& x, const basic_simd& y); + +template + bool + all_of(const basic_simd_mask&); + +// no way around a prefix: +template + concept simd_integral = /*...*/; + +template + concept simd_generic_integral = integral or simd_integral; +\end{lstlisting} + +Usage example: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd vf, const std::vector& data) { + auto iota = std::generate>([](int i) { return i; }); + auto chunk = std::copy_from(data.begin()); + auto chunk_swapped = std::gather_from(data, iota ^ 1); + auto chunk_swapped2 = std::permute(chunk, [](int i) { return i ^ 1; }); + assert(std::all_of(chunk_swapped == chunk_swapped2)); + + vf = std::select(vf > 1.f, 1.f, vf); + vf = std::exp(vf); + auto lo = std::min(iota, chunk); +} +\end{lstlisting} + +There is little variation possible for the above code. +The most important variation is using unqualified calls, relying on ADL: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd vf, const std::vector& data) { + auto iota = std::generate>([](int i) { return i; }); + auto chunk = std::copy_from(data.begin()); + auto chunk_swapped = gather_from(data, iota ^ 1); + auto chunk_swapped2 = permute(chunk, [](int i) { return i ^ 1; }); + assert(all_of(chunk_swapped == chunk_swapped2)); + + vf = select(vf > 1.f, 1.f, vf); + vf = exp(vf); + auto lo = min(iota, chunk); +} +\end{lstlisting} + +For \simdgeneric programming the example now looks like this: +\medskip\begin{lstlisting}[style=Vc] +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T simd_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T generic(T a, T b) { + return 2 * std::min(a, b); +} +\end{lstlisting} + +\begin{description} + \item[pros] + \begin{itemize} + \item Consistent. + \item[$\Rightarrow$] Simple to remember. + \item \simdgeneric interfaces can easily be provided. + \end{itemize} + + \item[cons] + \begin{itemize} + \item Nothing in e.g. \code{auto x = std::copy_from(data.begin())} hints + at the creation of a \simd object. + \item Non-\code{simd} overloads for the same names become questionable + as soon as the functionality isn't equivalent. (huge “name grab”) + + \item If we ever need to disambiguate an inconsistently overloaded term, + then it will need a \code{simd_} prefix. + \Eg the \code{simd_integral} concept would be such a term. + This could be considered less consistent than what we'd like to aim + for. + \end{itemize} +\end{description} + +\myrating{unacceptable “name grab” and potentially confusing overloads} diff --git a/P3287_exploration_of_namespaces_for_simd/alt3.tex b/P3287_exploration_of_namespaces_for_simd/alt3.tex new file mode 100644 index 0000000..72e7f99 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt3.tex @@ -0,0 +1,129 @@ +\subsection{Alternative 3: place everything but types into a namespace} + +\medskip\begin{lstlisting}[style=Vc] +namespace std { +template + class basic_simd; +} + +namespace std::Simd { // I don't even have one acceptable idea for a name + +template + V + generate(G&& gen); + +template + conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + basic_simd + exp(const basic_simd& x); + +template + basic_simd + min(const basic_simd& x, const basic_simd& y); + +template + bool + all_of(const basic_simd_mask&); + +template + concept integral = /*...*/; + +template + concept generic_integral = std::integral or Simd::integral; + +} +\end{lstlisting} + +Usage example: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd vf, const std::vector& data) { + auto iota = std::Simd::generate>([](int i) { return i; }); + auto chunk = std::Simd::copy_from(data.begin()); + auto chunk_swapped = std::Simd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = std::Simd::permute(chunk, [](int i) { return i ^ 1; }); + assert(std::Simd::all_of(chunk_swapped == chunk_swapped2)); + + vf = std::Simd::select(vf > 1.f, 1.f, vf); + vf = std::Simd::exp(vf); + auto lo = std::Simd::min(iota, chunk); +} +\end{lstlisting} + +There is little variation possible for the above code. +ADL doesn't work, but a namespace alias becomes interesting: +\medskip\begin{lstlisting}[style=Vc] +namespace smd = std::Simd; + +void f(std::simd vf, const std::vector& data) { + auto iota = smd::generate>([](int i) { return i; }); + auto chunk = smd::copy_from(data.begin()); + auto chunk_swapped = smd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = smd::permute(chunk, [](int i) { return i ^ 1; }); + assert(smd::all_of(chunk_swapped == chunk_swapped2)); + + vf = smd::select(vf > 1.f, 1.f, vf); + vf = smd::exp(vf); + auto lo = smd::min(iota, chunk); +} +\end{lstlisting} + +For \simdgeneric programming the example now looks like this: +\medskip\begin{lstlisting}[style=Vc] +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T simd_only(T a, T b) { + return 2 * std::simd::min(a, b); +} + +template +T generic(T a, T b) { + if constexpr (std::simd::integral) + return 2 * std::simd::min(a, b); + else + return 2 * std::min(a, b); +} +\end{lstlisting} + +\begin{description} + \item[pros] + \begin{itemize} + \item We are free to grab names out of the new namespace. + \item any? + \end{itemize} + + \item[cons] + \begin{itemize} + \item The type and functions being in different namespaces is awkward. + \item The required mismatch between the facility (“std::simd”) and the + namespace is frustrating. + \item[$\Rightarrow$] No possible good name for the namespace. + + \item \simdgeneric programming is barely possible (because it requires + too many constexpr-if branches). + \end{itemize} +\end{description} + +\myrating{unacceptable for lack of \simdgeneric programming; + ADL not working is not helping anything; +there must be a better alternative} diff --git a/P3287_exploration_of_namespaces_for_simd/alt4.tex b/P3287_exploration_of_namespaces_for_simd/alt4.tex new file mode 100644 index 0000000..778bbad --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt4.tex @@ -0,0 +1,67 @@ +\subsection{Alternative 4: make all non-member functions hidden friends} + +\medskip\begin{lstlisting}[style=Vc] +namespace std { +template + class basic_simd + { + /*...*/ + template + friend V + generate(G&& gen); + + template + friend conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + + template + friend simd, size()> + gather_from(const Rg&& in, const basic_simd& indexes, simd_flags f = {}); + + template + friend simd + permute(const basic_simd& v, PermuteGenerator&& fn); + + friend basic_simd + exp(const basic_simd& x); + + friend basic_simd + min(const basic_simd& x, const basic_simd& y); + }; + +template + class basic_simd_mask + { + /*...*/ + + template + friend auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + + friend bool + all_of(const basic_simd_mask&); + }; +} + +// can't be members or friends +template + concept simd_integral = /*...*/; + +template + concept simd_generic_integral = integral or simd_integral; +\end{lstlisting} + +Let's skip over usage examples because: + +\begin{description} + \item[cons] + \begin{itemize} + \item This doesn't even work! + No way to call e.g. \code{generate} or \code{copy_from}. + \item The requirement to always call unqualified is strange. + \item Makes \simdgeneric programming really hard. + \end{itemize} +\end{description} + +\myrating{Garbage} diff --git a/P3287_exploration_of_namespaces_for_simd/alt5.tex b/P3287_exploration_of_namespaces_for_simd/alt5.tex new file mode 100644 index 0000000..d511d43 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt5.tex @@ -0,0 +1,246 @@ +\subsection{Alternative 5: Place everything into a single namespace} +\label{sec:singlenamespace} + +\medskip\begin{lstlisting}[style=Vc] +namespace std::simd { + +template + class basic_simd; + +template + using simd = basic_simd>; + +template + V + generate(G&& gen); + +template + conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + basic_simd + exp(const basic_simd& x); + +template + basic_simd + min(const basic_simd& x, const basic_simd& y); + +template + bool + all_of(const basic_simd_mask&); + +template + concept integral = /*...*/; + +template + concept generic_integral = std::integral or std::simd::integral; + +} +\end{lstlisting} + +Conceivable \emph{variations} for the \std\code{simd} namespace are +\begin{itemize} + \item \std\code{datapar} (The \simd and \mask types are in the “Data-parallel types” section in the IS.) + \item \std\code{dp} (data-parallel) + \item \std\code{dpt} (data-parallel types) + \item \std\code{unseq} +\end{itemize} +Personally, I don't believe any of these are an improvement. + +However, I would suggest renaming \std\code{simd::}\MayBreak\mask to +\std\code{simd::}\MayBreak\code{basic_mask}, and accordingly \code{simd::simd_mask} +to \code{simd::mask}. + +Consequently, if we're reading the namespace as part of the type name +(\code{simd::mask}) we should consider renaming \code{simd::simd} to: +\begin{list}{}{ + \setlength{\topsep}{0pt}% + \setlength{\leftmargin}{7em}% + \setlength{\rightmargin}{0pt}% + \setlength{\labelwidth}{7em}% +} + + \item[\code{simd::vector}] + We often speak about “SIMD vectors”; so in principle this a good name. + However, I fear that using the heavily overloaded term “vector” has too + much potential for confusion. + Especially the use of \code{using namespace std; using namespace + std::simd;}\footnote{huge foot-gun, which WG21 members will quickly + recognize as such} or even just \code{using namespace std::simd} by + itself would lead to a lot of confusion. + + \item[\code{simd::vec}] + This name tries to avoid the confusion by spelling “vector” as an + abbreviation (and thus avoid the “hold on, why does it say \code{vector} + here?” moments when reviewing code) + + \item[\code{simd::value}] + Note the naming precedent in \code{valarray}, which is called “value + array”. + + \item[\code{simd::values}] + + \item[\code{simd::array}] + The static extent matches \std\code{array}; it's a \std\code{array} with + SIMD operations; also, I believe conversions between \code{simd} and + \std\code{array} of equal extent should be implicit\ldots +\end{list} + +From all of these, I'd prefer if we could use \code{simd::vector} --- and +in the library where this work originates it was called \code{Vc::Vector} +--- but I fear this will lead to confusion and just isn't worth the trouble. +It seems however that \code{simd::vec} could resolve that issue and still +be fairly close to the term we use in speech. +Next best\ldots{} \code{simd::array} is starting to grow on me. +This term was never considered before (IIRC\footnote{if I remember +correctly}). +It appeals to me be because I believe we should make CTAD and implicit +conversions work for \code{simd} $\leftrightarrow$ \code{array}. +In terms of bit-representation, they typically are the same thing. +They differ in alignment\footnote{Note that alignment can influence +\code{sizeof}.}, function argument passing\footnote{\Eg the Itanium ABI passes + \code{array} as two \code{XMM} registers and \code{simd} +as one \code{XMM} register.}, and whether you can apply operators that the +value-type provides. + +For now, I don't want to propose a name change. +But please give me feedback if you think I should / should not (propose a name +change). + +Usage example: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd::simd vf, const std::vector& data) { + auto iota = std::simd::generate>([](int i) { return i; }); + auto chunk = std::simd::copy_from(data.begin()); + auto chunk_swapped = std::simd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = std::simd::permute(chunk, [](int i) { return i ^ 1; }); + assert(std::simd::all_of(chunk_swapped == chunk_swapped2)); + + vf = std::simd::select(vf > 1.f, 1.f, vf); + vf = std::simd::exp(vf); + auto lo = std::simd::min(iota, chunk); +} +\end{lstlisting} + +This is fairly verbose, so a user might decide to rather rely on ADL: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd::simd vf, const std::vector& data) { + auto iota = std::simd::generate>([](int i) { return i; }); + auto chunk = std::simd::copy_from(data.begin()); + auto chunk_swapped = gather_from(data, iota ^ 1); + auto chunk_swapped2 = permute(chunk, [](int i) { return i ^ 1; }); + assert(all_of(chunk_swapped == chunk_swapped2)); + + vf = select(vf > 1.f, 1.f, vf); + vf = exp(vf); + auto lo = min(iota, chunk); +} +\end{lstlisting} + +But as we can see, ADL only works for some of the functions. +If the function requires a template argument or none of the arguments are a +\simd / \mask, then the call still must be qualified. +Consequently, if a user wants to reduce the character overhead, a namespace +alias might be better suited: +\medskip\begin{lstlisting}[style=Vc] +namespace smd = std::simd; + +void f(smd::simd vf, const std::vector& data) { + auto iota = smd::generate>([](int i) { return i; }); + auto chunk = smd::copy_from(data.begin()); + auto chunk_swapped = smd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = smd::permute(chunk, [](int i) { return i ^ 1; }); + assert(smd::all_of(chunk_swapped == chunk_swapped2)); + + vf = smd::select(vf > 1.f, 1.f, vf); + vf = smd::exp(vf); + auto lo = smd::min(iota, chunk); +} +\end{lstlisting} + +The \simdgeneric programming example from previous sections now looks like +this: +\medskip\begin{lstlisting}[style=Vc] +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T simd_only(T a, T b) { + return 2 * std::simd::min(a, b); +} + +template +T generic(T a, T b) { + if constexpr (std::simd::integral) + return 2 * std::simd::min(a, b); + else + return 2 * std::min(a, b); +} +\end{lstlisting} + +Another user might be looking for a way to qualify e.g. \code{} +functions such that they work both with \code{T} and \simdT. +To that end one needs to basically inline \std\code{simd} into \code{std} and +thus write: +\medskip\begin{lstlisting}[style=Vc] +namespace xstd { + using namespace std; + using namespace std::simd; +} + +void f(xstd::simd vf, const xstd::vector& data) { + auto iota = xstd::generate>([](int i) { return i; }); + auto chunk = xstd::copy_from(data.begin()); + auto chunk_swapped = xstd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = xstd::permute(chunk, [](int i) { return i ^ 1; }); + assert(xstd::all_of(chunk_swapped == chunk_swapped2)); + + vf = xstd::select(vf > 1.f, 1.f, vf); + vf = xstd::exp(vf); + auto lo = xstd::min(iota, chunk); +} +\end{lstlisting} + +I need to be convinced that the latter pattern isn't a liability, and +therefore I wouldn't allow this to go through code review without raising a +red flag. + +\begin{description} + \item[pros] + \begin{itemize} + \item We are free to grab names out of the new namespace. + \item ADL still works. + \item Consistent. + \item[$\Rightarrow$] Users only need to learn: “If it's in the + \std\code{simd} namespace then it works for \code{simd}s. + When searching for a function for \code{simd}, look in the + \std\code{simd} namespace.” + \end{itemize} + + \item[cons] + \begin{itemize} + \item \simdgeneric programming just got harder. + \item The class template name \std\code{simd::simd} is a bit awkward. + (There are alternative names that we could adopt instead.) + \end{itemize} +\end{description} + +\myrating{unacceptable for lack of \simdgeneric programming; +interesting if we get rid of the out-of-the-box requirement for constexpr-if} diff --git a/P3287_exploration_of_namespaces_for_simd/alt6.tex b/P3287_exploration_of_namespaces_for_simd/alt6.tex new file mode 100644 index 0000000..c930622 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt6.tex @@ -0,0 +1,155 @@ +\subsection{Alternative 6: Place everything but obvious overloads into a +single namespace} + +The preceding alternative probably went too far with moving \code{} +overloads and algorithms like \code{min}, \code{clamp}, etc. into the +\std\code{simd} namespace. +So let's keep all functions that are a clear overload (\code{f(simd)}) from +an existing function (\code{f(T)}) directly in the \code{std} namespace. +This is the “namespace equivalent” to the status-quo approach of whether a +\code{simd_} prefix is needed or not. + +\medskip\begin{lstlisting}[style=Vc] +namespace std::simd { + +template + class basic_simd; + +template + using simd = basic_simd>; + +template + V + generate(G&& gen); + +template + conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + bool + all_of(const basic_simd_mask&); + +template + concept integral = /*...*/; + +template + concept generic_integral = std::integral or std::simd::integral; + +} + +namespace std { + +template + simd::basic_simd + exp(const simd::basic_simd& x); + +template + simd::basic_simd + min(const simd::basic_simd& x, const simd::basic_simd& y); + +} +\end{lstlisting} + +Usage example: +\medskip\begin{lstlisting}[style=Vc] +void f(std::simd::simd vf, const std::vector& data) { + auto iota = std::simd::generate>([](int i) { return i; }); + auto chunk = std::simd::copy_from(data.begin()); + auto chunk_swapped = std::simd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = std::simd::permute(chunk, [](int i) { return i ^ 1; }); + assert(std::simd::all_of(chunk_swapped == chunk_swapped2)); + + vf = std::simd::select(vf > 1.f, 1.f, vf); + vf = std::exp(vf); + auto lo = std::min(iota, chunk); +} +\end{lstlisting} + +When relying on ADL, nothing changes compared to the example in the preceding +section. +However, if we now create a namespace alias and call everything fully +qualified, the necessary qualifications could be considered slightly +incoherent: + +\medskip\begin{lstlisting}[style=Vc] +namespace smd = std::simd; + +void f(smd::simd vf, const std::vector& data) { + auto iota = smd::generate>([](int i) { return i; }); + auto chunk = smd::copy_from(data.begin()); + auto chunk_swapped = smd::gather_from(data, iota ^ 1); + auto chunk_swapped2 = smd::permute(chunk, [](int i) { return i ^ 1; }); + assert(smd::all_of(chunk_swapped == chunk_swapped2)); + + vf = smd::select(vf > 1.f, 1.f, vf); + vf = std::exp(vf); + auto lo = std::min(iota, chunk); +} +\end{lstlisting} + +At this point all functions already work for \simdgeneric code (or can be made +to work with suitable overloads in the \std\code{simd} namespace). +If LEWG were to adopt this naming style, then we need to decide on a per +function basis, whether the function is “SIMD-only” or whether an overload for +the value-type is useful on its own. +For the latter, the function goes into \code{std} otherwise it needs to go +into \std\code{simd}. + +The \simdgeneric programming example from previous sections now looks like +this: +\medskip\begin{lstlisting}[style=Vc] +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T simd_only(T a, T b) { + return 2 * std::min(a, b); +} + +template +T generic(T a, T b) { + return 2 * std::min(a, b); +} +\end{lstlisting} + +\begin{description} + \item[pros] + \begin{itemize} + \item We are free to grab names out of the new namespace. + \item ADL works. + \item Fairly consistent. + \item[$\Rightarrow$] Users need to learn: “If it's in the \std\code{simd} + namespace then it works for \code{simd}s. + When searching for a function for \code{simd}, if the same function + exists / could exist for scalars look for it in \code{std}, otherwise + look in the \std\code{simd} namespace.” + \item \simdgeneric programming is straightforward to provide and use. + \end{itemize} + + \item[cons] + \begin{itemize} + \item The class template name \std\code{simd::simd} is a bit awkward. + + \item We have a mix of non-member functions in \code{std} and + \std\code{simd}. + \end{itemize} +\end{description} + +\myrating{acceptable; but not much different from the status quo --- not convinced this is actually \emph{better}} diff --git a/P3287_exploration_of_namespaces_for_simd/alt7.tex b/P3287_exploration_of_namespaces_for_simd/alt7.tex new file mode 100644 index 0000000..9b75d40 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/alt7.tex @@ -0,0 +1,183 @@ +\subsection{Alternative 7: Place \code{simd} into a single namespace with a different namespace for \simdgeneric interfaces} + +\medskip\begin{lstlisting}[style=Vc] +namespace std::simd { + +template + class basic_simd; + +template + using simd = basic_simd>; + +template + V + generate(G&& gen); + +template + conditional_t, simd>, V> + copy_from(It first, simd_flags f = {}); + +template + simd, basic_simd::size()> + gather_from(const Rg&& in, const basic_simd& indexes, + simd_flags f = {}); + +template + simd + permute(const basic_simd& v, PermuteGenerator&& fn); + +template + auto + select(const basic_simd_mask& c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +template + basic_simd + exp(const basic_simd& x); + +template + basic_simd + min(const basic_simd& x, const basic_simd& y); + +template + bool + all_of(const basic_simd_mask&); + +template + concept integral = /*...*/; + +} // std::simd + +namespace std::simd_generic { + +namespace scalar { + +template<@\vectorizable@ T, class G> + T + generate(G&& gen); + +template<@\vectorizable@ T, class It, class... Flags> + T + copy_from(It first, simd_flags f = {}); + +template + ranges::range_value_t + gather_from(const Rg&& in, Idx index, simd_flags f = {}); + +template + auto + select(bool c, const T& a, const U& b) + -> decltype(simd-select-impl(c, a, b)); + +using std::exp; + +using std::min; + +bool +all_of(same_as); + +} // (std::simd_generic::)scalar + +using namespace std::simd; + +using namespace std::simd_generic::scalar; + +template + concept integral = std::integral or std::simd::integral; + +} // std::simd_generic +\end{lstlisting} + +The usage example looks exactly like in \sect{sec:singlenamespace}. +There is also no difference with regard to ADL and using a namespace alias. + +However, the situation for \simdgeneric programming is rather different. +At this point a user can be very clear about “scalar-only” (\code{std}), +“simd-only” (\std\code{simd}), and \simdgeneric (\std\code{simd_generic}) +code. +Thus, our recurring example becomes: +\medskip\begin{lstlisting}[style=Vc] +template +template +T scalar_only(T a, T b) { + return 2 * std::min(a, b); +} + +T simd_only(T a, T b) { + return 2 * std::simd::min(a, b); +} + +template +T fun(T a, T b) { + return 2 * std::simd_generic::min(a, b); +} +\end{lstlisting} + +Now the namespace of the \code{integral} concept matches the namespace of the +functions that we need to use. +There's a clear mechanism from opting into \simdgeneric overloads --- or avoiding them when they are not required. +All the prevision definitions of SIMD-integral and \simdgeneric-integral +concepts didn't have this clear association with a set of function overloads. + +The ability to choose between \code{std::simd} and \code{std::simd_generic} +also provides another level of clarity in stating intent: Do you expect your +code to be called only with \simdT or also with \code{T}? + +Note that, as declared above, also \code{} overloads are in different +namespaces. +Thus, instead of writing \code{using std::exp}, I can now write \code{using +std::simd_generic::exp} and all unqualified \code{exp} calls are overloaded +for scalars and \code{simd}s. + +I expect that many users might be interested in shortening \std\code{simd} and +even more \std\code{simd_generic}. +If that's the case, we're going to see many namespace aliases for the two +namespaces. + +\begin{description} + \item[pros] + \begin{itemize} + \item We are free to grab names out of the new namespace. + \item ADL still works. + \item Consistent. + \item[$\Rightarrow$] Users only need to learn: “If it's in the + \std\code{simd} namespace then it works for \code{simd}s. + When searching for a function for \code{simd}, look in the + \std\code{simd} namespace. + When it needs to work generically for \code{simd} and scalars, just + switch to \std\code{simd_generic}.” + \item Opt-in \simdgeneric programming that is fairly “safe” with regard + to accidentally calling the wrong overload. + \end{itemize} + + \item[cons] + \begin{itemize} + \item The class template name \std\code{simd::simd} still is a bit + awkward. + \\(standard SIMD vector / \std\code{simd::vec}?) + \item \std\code{simd_generic} is too long and will be abbreviated with + different namespace aliases in different code bases\footnote{this is + normal in other languages, \eg Python}. + \end{itemize} +\end{description} + +\myrating{ + sold; feels good after implementing it; happy about the clear separation of + scalar / SIMD / \simdgeneric; happy about concise code through namespace + aliases +} + +\subsubsection{On renaming \code{std::simd::simd} to \code{std::simd::vec}} +Personally, I don't think \std\code{simd::simd} is a problem. +Especially, considering that users might introduce a namespace alias or even +--- heaven forbid --- import the whole \std\code{simd} (or +\std\code{simd_generic}) namespace into their local scope. +If \code{vec} needs to stand on its own without the \code{simd::} part of the +name, I fear we might lose clarity compared to \code{simd}. + +I believe the situation is different for \std\code{simd::simd_mask}, which, +in my opinion, can live without the \code{simd_} part in its name. +Thus, even after a \code{using namespace std::simd;} the alias template name +\code{mask} is expressive enough. +(Because \code{mask} only appears in proximity to \code{simd} --- if it +appears in code at all.) diff --git a/P3287_exploration_of_namespaces_for_simd/changelog.tex b/P3287_exploration_of_namespaces_for_simd/changelog.tex new file mode 100644 index 0000000..3a1644a --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/changelog.tex @@ -0,0 +1,5 @@ +\section{Changelog} +(placeholder) +%\begin{revision} +% \todo Everything +%\end{revision} diff --git a/P3287_exploration_of_namespaces_for_simd/main.tex b/P3287_exploration_of_namespaces_for_simd/main.tex new file mode 100644 index 0000000..2252056 --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/main.tex @@ -0,0 +1,260 @@ +\newcommand\wgTitle{Exploration of namespaces for std::simd} +\newcommand\wgName{Matthias Kretz } +\newcommand\wgDocumentNumber{D3287R0} +\newcommand\wgGroup{LEWG} +\newcommand\wgTarget{\CC{}26} +%\newcommand\wgAcknowledgements{Thanks to Daniel Towner, Ruslan Arutyunyan, Jonathan Müller, Jeff Garland, and Nicolas Morales for discussions and/or pull requests on this/previous paper(s).} + +\usepackage{mymacros} +\usepackage{wg21} +\setcounter{tocdepth}{2} % show sections and subsections in TOC +\hypersetup{bookmarksdepth=5} +\usepackage{changelog} +\usepackage{underscore} +\usepackage{multirow} + +\addbibresource{extra.bib} + +\newcommand\simd[1][]{\type{ba\-sic\_simd#1}\xspace} +\newcommand\simdT{\type{ba\-sic\_simd\MayBreak<\MayBreak{}T>}\xspace} +\newcommand\valuetype{\type{val\-ue\_type}\xspace} +\newcommand\referencetype{\type{ref\-er\-ence}\xspace} +\newcommand\mask[1][]{\type{ba\-sic\_simd\_mask#1}\xspace} +\newcommand\maskT{\type{ba\-sic\_simd\_mask\MayBreak<\MayBreak{}T>}\xspace} +\newcommand\wglink[1]{\href{https://wg21.link/#1}{#1}} +\newcommand\simdgeneric{SIMD-gener\-ic\xspace} + +\newcommand\nativeabi{\UNSP{native-abi}} +\newcommand\deducet{\UNSP{deduce-t}} +\newcommand\simdsizev{\UNSP{simd-size-v}} +\newcommand\simdsizetype{\UNSP{simd-size-type}} +\newcommand\simdselect{\UNSP{simd-select-impl}} +\newcommand\maskelementsize{\UNSP{mask-element-size}} +\newcommand\integerfrom{\UNSP{integer-from}} +\newcommand\constexprwrapperlike{\UNSP{constexpr-wrapper-like}} +\newcommand\vectorizable{\UNSP{vectorizable}} + +\renewcommand{\lst}[1]{Listing~\ref{#1}} +\renewcommand{\sect}[1]{Section~\ref{#1}} +\renewcommand{\ttref}[1]{Tony~Table~\ref{#1}} +\renewcommand{\tabref}[1]{Table~\ref{#1}} + +\newcommand\myrating[1]{\par\noindent{\color{Headings}\scshape{}my rating:} #1} + +\begin{document} +\selectlanguage{american} +\begin{wgTitlepage} + In recent discussions about \code{simd} in LEWG, notably on 2023-06-16 while + discussing \code{permute}, \code{expand}, and \code{compress}, there was a + request for a paper exploring placing all \code{simd} non-member functions + into a sub-namespace. + \ldots or potentially any other means of using namespaces to improve the + \code{simd} API. + + This paper explores a few ideas. +\end{wgTitlepage} + +\pagestyle{scrheadings} + +\input{changelog} +\input{strawpolls} + +\section{Introduction \& Motivation} + +Using the example of \std\code{permute(\simd, idx_perm)}, one of the unavoidable +LEWG discussions/decisions is about whether \code{simd} can grab the name +“permute”, potentially blocking its use for other facilities in the standard +library.\footnote{Just to clarify, I agree with the concern and I feel uneasy +with the need for \code{simd} to grab as many names as it would need to.} +With P3067R0 (“Provide named permutation functions for \std\code{simd}”), the +list of non-member functions to add to \std\ becomes: +\code{permute}, \code{expand}, \code{compress}, \code{grow}, \code{stride}, +\code{chunk}, \code{reverse}, \code{re\-peat_all}, \code{re\-peat_each}, +\code{transpose}, \code{zip}, \code{unzip}, \code{cat}, \code{ex\-tract}, +\code{rotate}, \code{shift_left}, \code{shift_right}, and \code{align}. +All of these names would likely need a \code{simd} prefix if they want to go +into \std. + +And then we're adding \simd overloads for all of \code{} and +\code{}, \ldots. + +So we need to understand whether there are viable alternatives to \code{simd} +naming. +This paper tries to explore the field as far as I believe is still sensible. +The goal is to come up with a consistent naming strategy for everything related +to \code{simd}. + +\subsection{\simdgeneric programming} + +In this paper I want to use the term \emph{\simdgeneric} programming. +Note that in the space of types, \simdT is a generalization of \code{T} or --- +vice-versa --- \code{T} is the degenerate case of \simdT. +(The same is true for \mask and \code{bool}.) +We've touched upon this when we talked about regularity and how \simdT is +designed to retain regularity of each individual element inside the \simd, +leading to something I called “data-parallel regularity” of \simdT, for lack of +an existing term. + +The \code{simd} design aims to allow users to replace \code{T} with \simdT in +their code without requiring any further code changes. +If this works (and because of branching on individual values of \code{T} it +cannot work for all code) I call such code \simdgeneric. + +The following text uses this term because the use of namespaces opens an +interesting facility to opt in and out of some aspects of \simdgeneric +programming. + +\section{Exploration} + +When exploring naming and namespacing, I use the following functions to showcase the effect. +I then try to come up with all ways to use and abuse the facilities. +In addition I mention the effect of the choice on \simdgeneric programming. +To complete the picture, I added a concept that seems like something we might +want to add in the future, but for which there is currently no proposal coming +forward. + +Note: we have to discuss the range vs. iterator argument to load/gather seperately. +This paper does not explore the issue. +I also removed \code{constexpr} and \code{noexcept} since they are irrelevant +to the exploration at hand. + +\begin{enumerate} + \item \label{fun:generator} \simd generator + + Status quo (P1928R9): + \medskip\begin{lstlisting}[style=Vc] +std::simd iota([](int i) { return i; }); + \end{lstlisting} + + \item \label{fun:load} \simd load from contiguous range + + Status quo (P1928R9): + \medskip\begin{lstlisting}[style=Vc] +std::vector data = {...}; +std::simd chunk(data.begin()); + \end{lstlisting} + + \item \label{fun:gather} \simd gather from contiguous range + + Status quo (P2664R6): + \medskip\begin{lstlisting}[style=Vc] +std::vector data = {/*...*/}; +std::simd idxs = /*...*/; +std::simd std::gather_from(data, idxs); + \end{lstlisting} + + \item \label{fun:permute} \simd permutations + + Status quo (P2664R6): + \medskip\begin{lstlisting}[style=Vc] +std::simd v = /*...*/; +std::simd v2 = std::permute(v, [](int i) { return i ^ 1; }); + \end{lstlisting} + + \item \label{fun:select} \simd ternary operator replacement + + Status quo (P1928R9): + \medskip\begin{lstlisting}[style=Vc] +std::simd v = /*...*/; +std::simd abs = std::simd_select(v >= 0, v, -v); + \end{lstlisting} + + \item \label{fun:math} Math functions and algorithms + + Status quo (P1928R9): + \medskip\begin{lstlisting}[style=Vc] +std::simd x = /*...*/; +std::simd y = std::exp(x); +std::simd z = std::min(x, y); + \end{lstlisting} + + \item \label{fun:maskred} Mask reductions + + Status quo (P1928R9): + \medskip\begin{lstlisting}[style=Vc] +std::simd x = /*...*/; +if (std::all_of(x > 0)) /*...*/ + \end{lstlisting} + + \item \label{concept} Simd concepts + \begin{itemize} + \item Constrain whether a type is a \simdT with \std\code{integral}. + \item Constrain whether a type is either \std\code{integral} or a \simdT + with \std\code{integral}. + \end{itemize} + +\end{enumerate} + +\subsection{Status quo (latest revision of \code{simd} papers)} +\begin{description} + \item[pros] + \begin{itemize} + \item \std\code{simd} is as concise as it could possibly be. + + \item Fairly good support for \simdgeneric programming. + \end{itemize} + + \item[cons] + \begin{itemize} + \item We have a mix of non-member functions with and without + \code{simd_} prefix. + + \item Most non-member functions would be nicer to read in code without + the \code{simd} prefix. + We introduce the prefix only because we are wary of the “name grab” + in \code{std}. + \Ie the motivation for the current naming scheme isn't the design of + the \code{simd} API, but the freedom to evolve the standard library + in the future. + + \item Load and gather (which are very similar in loading a SIMD + “register” from a contiguous range of values) are inconsistent: One + uses a constructor and member function, the other only a non-member + function. + + \item Loads, stores, and the \code{simd} generator constructor cannot + be used in \simdgeneric code. + \end{itemize} +\end{description} + +\pagebreak\input{alt1} +\pagebreak\input{alt2} +\pagebreak\input{alt3} +\pagebreak\input{alt4} +\pagebreak\input{alt5} +\pagebreak\input{alt6} +\pagebreak\input{alt7} + +\pagebreak \section{Proposed polls} + +Any vote would be against the status quo, which so far can be summarized as: +\begin{itemize} + \item types and functions go directly into \code{std} + + \item when naming a function for \code{simd}, + \begin{itemize} + \item if the same function exists / could exist for scalars or a range: + no \code{simd_} prefix, + \item otherwise the function name needs a \code{simd_} prefix + \end{itemize} + + \item traits and types need a \code{simd} in their name +\end{itemize} + +\wgPoll{Adopt Alternative 7 from \wgDocumentNumber\ while renaming + (\code{basic_})\code{simd_mask} to (\code{basic_})\code{mask} (without +making a decision on non-member load, store, and generate)} +{&&&&} + +\wgPoll{Adopt Alternative 7 from \wgDocumentNumber\ while renaming + (\code{basic_})\code{simd_mask} to (\code{basic_})\code{mask} and + (\code{basic_})\code{simd} to (\code{basic_})\code{vec} (without making a +decision on non-member load, store, and generate)} +{&&&&} + +\section{Wording}\label{sec:wording} + +TBD + +\end{document} +% vim: sw=2 sts=2 ai et tw=0 diff --git a/P3287_exploration_of_namespaces_for_simd/strawpolls.tex b/P3287_exploration_of_namespaces_for_simd/strawpolls.tex new file mode 100644 index 0000000..fd8f97d --- /dev/null +++ b/P3287_exploration_of_namespaces_for_simd/strawpolls.tex @@ -0,0 +1,2 @@ +\section{Straw Polls} +(placeholder) diff --git a/listingscpp.sty b/listingscpp.sty index 308392e..98b8dec 100644 --- a/listingscpp.sty +++ b/listingscpp.sty @@ -88,8 +88,10 @@ keywords=[5]{array,deque,vector,map,unordered_map,common_type,common_type_t, reference_wrapper,Incomplete,Holder,Iterator,IteratorImpl,Data,Ptr,Testable,Unused,Wrap, type, simd,simd_mask,native_simd,fixed_size_simd,native_simd_mask,fixed_size_simd_mask, + basic_simd,basic_simd_mask, duration,time_point,integer,fractional,fixed_point,is_bounded_integer,rational, - A,B,C,D,E,F,G,I,R,T,U,X,Y,Z, + A,B,C,D,E,F,G,I,R,T,U,V,X,Y,Z, + It,Flags, A0,B0,C0,XRef, Point,Abi, memory_alignment,element_aligned_tag,vector_aligned_tag,overaligned_tag,deduce,deduce_t, @@ -127,6 +129,11 @@ keywords=[11]{const_cast,static_cast,dynamic_cast,reinterpret_cast,static_pointe moredelim=**[s][\color{directives}\bfseries]{[[}{]]}, moredelim=**[s][\color{directives}\bfseries]{__attribute__((}{))}, moredelim=**[s][\color{namespacequal}]{std:}{:}, +moredelim=**[s][\color{namespacequal}]{xstd:}{:}, +moredelim=**[s][\color{namespacequal}]{stdx:}{:}, +moredelim=**[s][\color{namespacequal}]{smd:}{:}, +moredelim=**[s][\color{namespacequal}]{simd:}{:}, +moredelim=**[s][\color{namespacequal}]{simd_generic:}{:}, moredelim=**[s][\color{namespacequal}]{bounded:}{:}, moredelim=**[s][\color{namespacequal}]{experimental:}{:}, moredelim=*[directive]\#, @@ -136,7 +143,7 @@ include,pragma,undef,warning} \iflstcpp@mono@ \definecolor{identifier}{cmyk}{0, 0, 0, 1} -\definecolor{namespacequal}{cmyk}{0, 0, 0, .5} +\definecolor{namespacequal}{cmyk}{0, 0, 0, .7} \definecolor{constants}{cmyk}{0, 0, 0, 1} \definecolor{types}{gray}{0.2} \definecolor{storageclass}{gray}{0.2} @@ -147,7 +154,7 @@ include,pragma,undef,warning} \definecolor{lstoverlay}{gray}{0.4} \else \definecolor{identifier}{cmyk}{0, 0, 0, 1} -\definecolor{namespacequal}{cmyk}{0, 0, 0, .5} +\definecolor{namespacequal}{cmyk}{0, 0, 0, .7} \definecolor{constants}{rgb}{0.3, 0, 0} \definecolor{types}{cmyk}{0.9, 0.2, 0.0, 0.4} \definecolor{storageclass}{cmyk}{0.8, 0, 1.0, 0.4} diff --git a/wg21.sty b/wg21.sty index 5407a1b..7eca7be 100644 --- a/wg21.sty +++ b/wg21.sty @@ -235,28 +235,34 @@ %\def\@myheadingrule{\nopagebreak\titleline{\color{HeadingRule}\titlerule}} \def\@myheadingrule{\vspace{0.2\baselineskip}\nopagebreak{\textcolor{HeadingRule}{\hrule height .4pt}}\nopagebreak} -\ifdefined\sectionlinesformat % On Travis VMs TeX Live is too old. KOMA Script doesn't have \sectionlinesformat yet. - \renewcommand{\sectionlinesformat}[4]{% - \@hangfrom{\hskip #2#3}{\hfill \Ifstr{#1}{section}{\MakeUppercase{#4}}{\MakeLowercase{#4}}}\nopagebreak% - \Ifstr{#1}{section}{\@myheadingrule}{}% - \Ifstr{#1}{subsection}{\@myheadingrule}{}% - } +\newsavebox\@wgtmpbox + +\renewcommand{\sectionlinesformat}[4]{% + %\@hangfrom{\hskip #2#3}{\hfill \Ifstr{#1}{section}{\MakeUppercase{#4}}{\MakeLowercase{#4}}}\nopagebreak% + \sbox\@wgtmpbox{\hskip #2#3}% + \makebox[\textwidth][s]{% + \parbox[b]{\wd\@wgtmpbox}{\usebox\@wgtmpbox}\hfill% + \parbox[b]{\textwidth-\wd\@wgtmpbox}{\raggedleft% + \Ifstr{#1}{section}{\MakeUppercase{#4}}{\MakeLowercase{#4}}}\nopagebreak% + }% + \Ifstr{#1}{section}{\@myheadingrule}{}% + \Ifstr{#1}{subsection}{\@myheadingrule}{}% +} - \renewcommand*{\sectionformat}{{\sectionNumberFont\thesection\autodot}\enskip} - \setkomafont{section}{\large\color{Headings}\scshape\addfontfeature{LetterSpace=4}} +\renewcommand*{\sectionformat}{{\sectionNumberFont\thesection\autodot}\enskip} +\setkomafont{section}{\large\color{Headings}\scshape\addfontfeature{LetterSpace=4}} - \renewcommand*{\subsectionformat}{\spacedlowsmallcaps{\thesubsection\autodot}\enskip} - \setkomafont{subsection}{\color{Headings}\scshape\addfontfeature{LetterSpace=7}} +\renewcommand*{\subsectionformat}{\spacedlowsmallcaps{\thesubsection\autodot}\enskip} +\setkomafont{subsection}{\color{Headings}\scshape\addfontfeature{LetterSpace=7}} - \renewcommand*{\subsubsectionformat}{\spacedlowsmallcaps{\thesubsubsection\autodot}\enskip} - \setkomafont{subsubsection}{\color{Headings}\scshape\addfontfeature{LetterSpace=7}} +\renewcommand*{\subsubsectionformat}{\spacedlowsmallcaps{\thesubsubsection\autodot}\enskip} +\setkomafont{subsubsection}{\color{Headings}\scshape\addfontfeature{LetterSpace=7}} - \renewcommand*{\paragraphformat}{\theparagraph\autodot\enskip} - \setkomafont{paragraph}{\scshape\addfontfeature{LetterSpace=7}} +\renewcommand*{\paragraphformat}{\theparagraph\autodot\enskip} +\setkomafont{paragraph}{\scshape\addfontfeature{LetterSpace=7}} - \renewcommand*{\subparagraphformat}{\thesubparagraph\autodot\enskip} - \setkomafont{subparagraph}{\scshape\addfontfeature{LetterSpace=7}} -\fi +\renewcommand*{\subparagraphformat}{\thesubparagraph\autodot\enskip} +\setkomafont{subparagraph}{\scshape\addfontfeature{LetterSpace=7}} % descriptionlabels \renewcommand{\descriptionlabel}[1]{\hspace*{\labelsep}\spacedsmallcaps{#1}}