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 element
  • fixed_size: storing a specified number of elements
  • compatible: ensures ABI compatibility
  • native: most efficient
  • max_fixed_size: maximum number of elements guaranteed to be supported by fixed_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.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Embedded Programming with Modern C++": (open)
  • "Generic Programming (Templates) with C++": (open)
  • "Clean Code: Best Practices for Modern C++": July 2025
  • 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)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org