C++ Logo

std-proposals

Advanced search

Re: [std-proposals] TBAA and extended floating-point types

From: Tom Honermann <tom_at_[hidden]>
Date: Wed, 27 Aug 2025 20:39:02 -0400
On 8/27/25 5:50 PM, Paul Caprioli wrote:
> Thanks, Tom. I'd like to make the following observations:
>
>> The goal is to temporarily replace objects of type A with objects of type B
>> while preserving the object representation, then accessing/modifying
>> the replacement objects using only type B, then replace the
>> objects of type B with objects of type A while again
>> preserving the object representation in such a way that
>> pointers/references to the original set of objects transparently
>> refer to the new set of objects. Key to making this work is
>> specifying that these operations do not end the lifetime of any
>> enclosing objects.
> It seems that it would be a big change to the abstract machine if starting the lifetime of objects of type B did not end the lifetime of objects of type A (which formerly occupied the same storage).
I think the lifetimes of the (sub)objects of type A do need to end. What
needs to not end is their enclosing objects. In the example I provided,
the lifetime of the array object owned by the vector must not end (note
that the converted elements might not include all elements of the
array). Similarly, if the array were a data member of a class type /C/,
the in-place-converting-cast thing must not end the lifetime of the
enclosing object of type /C/.
>
>> std::inplace_converting_array_cast<std::float64_t>(x.data(), x.size());
>> std::inplace_converting_array_cast<std::float64_t>(y.data(), y.size());
>>
>> daxpy(n,std::bitcast<std::float64_t>(alpha), x.data(), y.data());
>>
>> std::inplace_converting_array_cast<double>(y.data(), y.size());
>> std::inplace_converting_array_cast<double>(x.data(), x.size());
> A minor point is thatstd::bitcast<std::float64_t>(alpha) is not needed. One can just write alpha and implicit conversion will work.
Agreed, I forgot that implicit conversions are specified for these types.
>
> However, x.data() is still double*, so in the daxpy call one would need reinterpret_cast<std::float64_t*>(x.data()), and similarly for y.data().
> So,std::inplace_converting_array_cast<std::float64_t> could, for convenience, return astd::float64_t*.
Yes, absolutely. I had intended to write exactly what you did below, but
got distracted thinking about the general problem and forgot to add the
pointers. Sorry about that.
>
> std::float64_t* x_ptr =std::inplace_converting_array_cast<std::float64_t>(x.data(), x.size());
> std::float64_t* y_ptr =std::inplace_converting_array_cast<std::float64_t>(y.data(), y.size());
>
> daxpy(n, alpha, x_ptr, y_ptr);
>
> std::inplace_converting_array_cast<double>(y_ptr, y.size());
> std::inplace_converting_array_cast<double>(x_ptr, x.size());
>
> Though, it seems like a fundamental change thatstd::inplace_converting_array_cast() has the effect of laundering all pointers that point to a given address.
> I think that's what it does--after all the code above, the vectors' pointers to double are again valid.
Exactly.
> If that direction seems promising, it might be worth brainstorming on something more general.
> Maybe,std::launder_all_pointers(void *,std::size_t)

You need something that TBAA can be made aware of so that the compiler
knows when it is necessary to perform reloads. The actual pointer value
and number of elements aren't particularly important for that; they are
more useful for sanitizers or for constant evaluation (if these
operations were to be permitted during constant evaluation where UB has
to be detected).

For a more blunt instrument, see SG16 #67 (Alias barriers; a replacement
for the ICU hack) <https://github.com/sg16-unicode/sg16/issues/67>.

> Personally, I don't see this as promising and don't intend to propose it, but it is interesting, and I appreciate your time and effort.
This is the only approach I've been able to come up with that I think
has a chance of working with the existing memory and object models while
preserving TBAA and without being overly structural. It would be a very
sharp edged tool.
>
> It's worth noting that GCC, for example, has the flag -fno-strict-aliasing
> Possibly compilers could offer something more restrictive, such as -fno-fp-strict-aliasing
> That may be a practical solution, but then the code isn't really C++ any more; it's a custom dialect.

Compilers could offer such options and the actual changes that would be
needed for GCC and Clang are small. But yes, the options would only be
useful for writing non-portable code.

Tom.

Received on 2025-08-28 00:39:07