This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 29.10.9.4 [simd.mask.unary] Status: WP Submitter: Matthias Kretz Opened: 2025-09-15 Last modified: 2025-11-11
Priority: 1
View all other issues in [simd.mask.unary].
View all issues with WP status.
Discussion:
Addresses DE 298
29.10.9.4 [simd.mask.unary] spells out the return type with the ABI tag of
the basic_mask specialization. That's problematic / overconstrained.
Consider Intel SandyBridge/IvyBridge-like targets:
vec<float>::size() -> 8 vec<int>::size() -> 4 mask<float>::size() -> 8
The ABI tag in this case encodes for vec<float> that one object holds 8
elements and is passed via one register. vec<int> uses a
different ABI tag that says 4 elements passed via one register.
vec<int, 8>'s ABI tag says 8 elements passed via two registers.
+mask<float>() return? The working draft says it must
return a basic_vec<int, mask<float>::abi_type>. And
mask<float>::abi_type is constrained to be the same as
vec<float>::abi_type. The working draft thus makes it
impossible to implement ABI tags that encode number of elements + number of
registers (+ bit-masks vs. vector-masks, but that's irrelevant for this
issue). Instead, an ABI tag would have to encode the native SIMD width of all
vectorizable types. And that's unnecessarily making compatible types
incompatible. Also we make it harder to add to the set of vectorizable types
in the future.The issue is even worse for an implementation that implements
vec<complex<T>> using different ABI tags. Encoding
whether the value-type is complex into the ABI is useful because it impacts
how the mask is stored (mask<complex<float>, 8> is
internally stored as a 16-element bit-mask (for interleaved complex), while
mask<double, 8> is stored as an 8-element bit-mask). The ABI
tag can also be used to implement interleaved vs. contiguous storage, which
is useful for different architectures. If we require
+mask<complex<float>>() to be of a different type than
any vec<long long> would ever be, that's just brittle and
unnecessary template bloat.
[2025-10-17; Reflector poll.]
Set priority to 1 after reflector poll.
"Should be addressed together with 4238(i)."
Previous resolution [SUPERSEDED]:
This wording is relative to N5014.
Modify 29.10.2 [simd.expos] as indicated:
using simd-size-type = see below; // exposition only template<size_t Bytes> using integer-from = see below; // exposition only template<class T, class Abi> constexpr simd-size-type simd-size-v = see below; // exposition only template<class T> constexpr size_t mask-element-size = see below; // exposition only template <size_t Bytes, class Abi> using simd-vec-from-mask-t = see below; // exposition only […]Modify 29.10.2.1 [simd.expos.defn] as indicated:
template<class T> constexpr size_t mask-element-size = see below; // exposition only-4-
mask-element-size<basic_mask<Bytes, Abi>>has the valueBytes.template <size_t Bytes, class Abi> using simd-vec-from-mask-t = see below;-?-
-?-simd-vec-from-mask-t<Bytes, Abi>is an alias for an enabled specialization ofbasic_vecif and only ifbasic_mask<Bytes, Abi>is a data-parallel type andinteger-from<Bytes>is valid and a vectorizable type.simd-vec-from-mask-t<Bytes, Abi>::size() == basic_mask<Bytes, Abi>::size()istrue. -?-typename simd-vec-from-mask-t<Bytes, Abi>::value_typeisinteger-from<Bytes>Modify 29.10.9.1 [simd.mask.overview], class template
basic_mask overviewsynopsis, as indicated:namespace std::simd { template<size_t Bytes, class Abi> class basic_mask { public: […] // 29.10.9.4 [simd.mask.unary], basic_mask unary operators constexpr basic_mask operator!() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator+() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator-() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator~() const noexcept; […] }Modify 29.10.9.4 [simd.mask.unary] as indicated:
constexpr basic_mask operator!() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator+() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator-() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>simd-vec-from-mask-t<Bytes, Abi> operator~() const noexcept;-1- Let
-2- Returns: […]opbe the operator.
[2025-11-04; Matthias Kretz provides new wording]
This also resolves 4238(i) and addresses DE 297.
[Kona 2025-11-04; approved by LWG. Status changed: New → Immediate.]
[Kona 2025-11-08; Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N5014.
Modify 29.10.9.1 [simd.mask.overview], class template basic_mask overview synopsis, as indicated:
namespace std::simd {
template<size_t Bytes, class Abi> class basic_mask {
public:
[…]
// 29.10.9.4 [simd.mask.unary], basic_mask unary operators
constexpr basic_mask operator!() const noexcept;
constexpr basic_vec<integer-from<Bytes>, Abi>see below operator+() const noexcept;
constexpr basic_vec<integer-from<Bytes>, Abi>see below operator-() const noexcept;
constexpr basic_vec<integer-from<Bytes>, Abi>see below operator~() const noexcept;
[…]
}
Modify 29.10.9.4 [simd.mask.unary] as indicated:
constexpr basic_mask operator!() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>see below operator+() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>see below operator-() const noexcept; constexprbasic_vec<integer-from<Bytes>, Abi>see below operator~() const noexcept;-1- Let
-2- Returns: A data-parallel object where the i-th element is initialized to the results of applyingopbe the operator.optooperator[](i)for all i in the range of [0,size()). -?- Remarks: If there exists a vectorizable signed integer typeIsuch thatsizeof(I) == Bytesistrue,operator+,operator-, andoperator~return an enabled specializationRofbasic_vecsuch thatR::value_typedenotesinteger-from<Bytes>andR::size() == size()istrue. Otherwise, these operators are defined as deleted and their return types are unspecified.