Data-Parallel Types: simd_mask
Thanks to simd_mask
, conditional execution of operations on data-parallel types is possible.

Unfortunately, in my last article, Data-Parallel Types – A First Example, I forgot to introduce one of the new library functions. I will make up for that in this article.
Where Expression
The new keyword where
creates a so-called where expression. This allows the elements of a SIMD vector to be addressed conditionally.
The following example illustrates this behavior:
// where.cpp #include <experimental/simd> #include <iostream> #include <string_view> namespace stdx = std::experimental; void println(std::string_view name, auto const& a) { std::cout << name << ": "; for (std::size_t i{}; i != std::size(a); ++i) std::cout << a[i] << ' '; std::cout << '\n'; } template<class A> stdx::simd<int, A> my_abs(stdx::simd<int, A> x) { where(x < 0, x) = -x; // Set elements where x is negative to their absolute value return x; } int main() { const stdx::native_simd<int> a = 1; println("a", a); const stdx::native_simd<int> b([](int i) { return i - 2; }); println("b", b); const auto c = a + b; println("c", c); const auto d = my_abs(c); println("d", d); }
The where
function is used in the my_abs
function: where(x < 0, x) = -x
; . This expression causes all elements of the SIMD vector that are less than zero to be set to their absolute value. The following screenshot shows the output of the program:

In this case, SSE2 commands are used. The SIMD vector is 128 bits in size.
The where
expression can be parameterized with a bool
expression or a simd_mask
.
simd_mask
This allows the previous program where.cpp
to also be implemented by using a simd_mask
. The following program shows the application of the simd_mask
.
// whereMask.cpp #include <experimental/simd> #include <iostream> #include <string_view> namespace stdx = std::experimental; void println(std::string_view name, auto const& a) { std::cout << std::boolalpha << name << ": "; for (std::size_t i{}; i != std::size(a); ++i) std::cout << a[i] << ' '; std::cout << '\n'; } int main() { const stdx::native_simd<int> a = 1; println("a", a); const stdx::native_simd<int> b([](int i) { return i - 2; }); println("b", b); const auto c = a + b; println("c", c); const stdx::native_simd_mask x = c < 0; println("x", x); auto d = c; where(x, d) *= -1; println("d", d); }
I would like to begin my explanation with the last five lines of the main
function. First, I create the simd_mask x
by applying the predicate c < 0
to each element of the SIMD vector c
. The mask x
has the same length as the SIMD vector, but only contains truth values. To ensure that these truth values are displayed as true
or false
and not as 1
or 0
, I have added the stream manipulator std::boolalpha
to the println
function. In addition, I have to initialize the SIMD vector d
with c
, since c
is constant. Now the where expression where(x, d) *= -1
can be applied to d
. Each element of the SIMD vector d
is negated if the mask has the value true.
The following screenshot shows the output of the program:

The data type simd_mask
is very similar to the data type simd
. The main difference is that simd
can accept all standard integer types, character types, and the types float
and double
. In contrast, simd_mask
only supports Boolean values.
Here is the definition of simd_mask
:
template<size_t Bytes, class Abi> class basic_simd_mask
The Abi
tag determines the number of elements and their memory. For the sake of completeness, here are the ABI tags again:
scalar
: storing a single elementfixed_size
: storing a specified number of elementscompatible
: ensures ABI compatibilitynative
: most efficientmax_fixed_size
: maximum number of elements guaranteed to be supported byfixed_size
Similar to simd
, simd_mask
also has two aliases:
template< size_t Bytes, int N > using fixed_size_simd_mask = simd_mask<Bytes, simd_abi::fixed_size<N>> template< size_t Bytes > using native_simd_mask = simd_mask<Bytes, simd_abi::native<Bytes>>
What’s next?
In what will be my last article on data-parallel types for the time being, I would like to discuss the special functions for these types.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, Honey Sukesan, bruce_lee_wayne, Silviu Ardelean, schnapper79, Seeker, and Sundareswaran Senthilvel.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | ![]() |
My special thanks to PVS-Studio | ![]() |
My special thanks to Tipi.build | ![]() |
My special thanks to Take Up Code | ![]() |
My special thanks to SHAVEDYAKS | ![]() |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org