Skip to content

Commit d7720c6

Browse files
committed
New issue from Matthias Kretz: "ABI tag in return type of [simd.mask.unary] is overconstrained"
1 parent b0d4109 commit d7720c6

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

xml/issue4376.xml

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4376" status="New">
5+
<title>ABI tag in return type of [simd.mask.unary] is overconstrained</title>
6+
<section>
7+
<sref ref="[simd.mask.unary]"/>
8+
</section>
9+
<submitter>Matthias Kretz</submitter>
10+
<date>15 Sep 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
<sref ref="[simd.mask.unary]"/> spells out the return type with the ABI tag of
16+
the `basic_mask` specialization. That's problematic / overconstrained.
17+
</p>
18+
<ol>
19+
<li><p>Consider Intel SandyBridge/IvyBridge-like targets:
20+
</p>
21+
<blockquote><pre>
22+
vec&lt;float&gt;::size() -&gt; 8
23+
vec&lt;int&gt;::size() -&gt; 4
24+
mask&lt;float&gt;::size() -&gt; 8
25+
</pre></blockquote>
26+
<p>
27+
The ABI tag in this case encodes for <tt>vec&lt;float&gt;</tt> that one object holds 8
28+
elements and is passed via <em>one</em> register. <tt>vec&lt;int&gt;</tt> uses a
29+
different ABI tag that says 4 elements passed via <em>one</em> register.
30+
<tt>vec&lt;int, 8&gt;</tt>'s ABI tag says 8 elements passed via <em>two</em> registers.
31+
<p/>
32+
Now what should <tt>+mask&lt;float&gt;()</tt> return? The working draft says it must
33+
return a <tt>basic_vec&lt;int, mask&lt;float&gt;::abi_type&gt;</tt>. And
34+
<tt>mask&lt;float&gt;::abi_type</tt> is constrained to be the same as
35+
<tt>vec&lt;float&gt;::abi_type</tt>. The working draft thus makes it
36+
impossible to implement ABI tags that encode number of elements + number of
37+
registers (+ bit-masks vs. vector-masks, but that's irrelevant for this
38+
issue). Instead, an ABI tag would have to encode the native SIMD width of all
39+
vectorizable types. And that's unnecessarily making compatible types
40+
incompatible. Also we make it harder to add to the set of vectorizable types
41+
in the future.</p></li>
42+
<li><p>The issue is even worse for an implementation that implements
43+
<tt>vec&lt;complex&lt;T&gt;&gt;</tt> using different ABI tags. Encoding
44+
whether the value-type is complex into the ABI is useful because it impacts
45+
how the mask is stored (<tt>mask&lt;complex&lt;float&gt;, 8&gt;</tt> is
46+
internally stored as a 16-element bit-mask (for interleaved `complex`), while
47+
<tt>mask&lt;double, 8&gt;</tt> is stored as an 8-element bit-mask). The ABI
48+
tag can also be used to implement interleaved vs. contiguous storage, which
49+
is useful for different architectures. If we require
50+
<tt>+mask&lt;complex&lt;float&gt;&gt;()</tt> to be of a different type than
51+
any <tt>vec&lt;long long&gt;</tt> would ever be, that's just brittle and
52+
unnecessary template bloat.</p></li>
53+
</ol>
54+
</discussion>
55+
56+
<resolution>
57+
<p>
58+
This wording is relative to <paper num="N5014"/>.
59+
</p>
60+
61+
<ol>
62+
63+
<li><p>Modify <sref ref="[simd.expos]"/> as indicated:</p>
64+
65+
<blockquote>
66+
<pre>
67+
using <i>simd-size-type</i> = <i>see below</i>; // <i>exposition only</i>
68+
template&lt;size_t Bytes&gt; using <i>integer-from</i> = <i>see below</i>; // <i>exposition only</i>
69+
70+
template&lt;class T, class Abi&gt;
71+
constexpr <i>simd-size-type</i> <i>simd-size-v</i> = <i>see below</i>; // <i>exposition only</i>
72+
template&lt;class T&gt; constexpr size_t <i>mask-element-size</i> = <i>see below</i>; // <i>exposition only</i>
73+
74+
<ins>template &lt;size_t Bytes, class Abi&gt;
75+
using <i>simd-vec-from-mask-t</i> = <i>see below</i>; // <i>exposition only</i></ins>
76+
[&hellip;]
77+
</pre>
78+
</blockquote>
79+
80+
</li>
81+
82+
<li><p>Modify <sref ref="[simd.expos.defn]"/> as indicated:</p>
83+
84+
<blockquote>
85+
<pre>
86+
template&lt;class T&gt; constexpr size_t <i>mask-element-size</i> = <i>see below</i>; // <i>exposition only</i>
87+
</pre>
88+
<blockquote>
89+
<p>
90+
-4- <tt><i>mask-element-size</i>&lt;basic_mask&lt;Bytes, Abi&gt;&gt;</tt> has the value `Bytes`.
91+
</p>
92+
</blockquote>
93+
<pre>
94+
<ins>template &lt;size_t Bytes, class Abi&gt;
95+
using <i>simd-vec-from-mask-t</i> = <i>see below</i>;</ins>
96+
</pre>
97+
<blockquote>
98+
<p>
99+
<ins>-?- <tt><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</tt> is an alias for an enabled
100+
specialization of `basic_vec` if and only if <tt>basic_mask&lt;Bytes, Abi&gt;</tt> is a
101+
data-parallel type and <tt><i>integer-from</i>&lt;Bytes&gt;</tt> is valid and a vectorizable type.</ins>
102+
<p/>
103+
<ins>-?- <tt><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;::size() == basic_mask&lt;Bytes, Abi&gt;::size()</tt>
104+
is `true`.</ins>
105+
<p/>
106+
<ins>-?- <tt>typename <i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;::value_type</tt> is
107+
<tt><i>integer-from</i>&lt;Bytes&gt;</tt></ins>
108+
</p>
109+
</blockquote>
110+
</blockquote>
111+
112+
</li>
113+
114+
<li><p>Modify <sref ref="[simd.mask.overview]"/>, class template `basic_mask overview` synopsis, as indicated:</p>
115+
116+
<blockquote>
117+
<pre>
118+
namespace std::simd {
119+
template&lt;size_t Bytes, class Abi&gt; class basic_mask {
120+
public:
121+
[&hellip;]
122+
// <i><sref ref="[simd.mask.unary]"/>, basic_mask unary operators</i>
123+
constexpr basic_mask operator!() const noexcept;
124+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator+() const noexcept;
125+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator-() const noexcept;
126+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator~() const noexcept;
127+
[&hellip;]
128+
}
129+
</pre>
130+
</blockquote>
131+
132+
</li>
133+
134+
<li><p>Modify <sref ref="[simd.mask.unary]"/> as indicated:</p>
135+
136+
<blockquote>
137+
<pre>
138+
constexpr basic_mask operator!() const noexcept;
139+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator+() const noexcept;
140+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator-() const noexcept;
141+
constexpr <del>basic_vec&lt;<i>integer-from</i>&lt;Bytes&gt;, Abi&gt;</del><ins><i>simd-vec-from-mask-t</i>&lt;Bytes, Abi&gt;</ins> operator~() const noexcept;
142+
</pre>
143+
<blockquote>
144+
<p>
145+
-1- Let <tt><i>op</i></tt> be the operator.
146+
<p/>
147+
-2- <i>Returns</i>: [&hellip;]
148+
</p>
149+
</blockquote>
150+
</blockquote>
151+
152+
</li>
153+
154+
</ol></resolution>
155+
156+
</issue>

0 commit comments

Comments
 (0)