Date: Fri, 26 Feb 2016 18:03:52 +0000
On 02/26/2016 02:26 PM, Hubert Tong wrote:
> On Fri, Feb 26, 2016 at 7:12 AM, Robert Haberlach <rh633_at_[hidden] <mailto:rh633_at_[hidden]>> wrote:
>
> I apologize in advance if this was discussed before; I didn't check the entire archive. Consider
>
> static_assert(alignof(float) >= alignof(int) && sizeof(float) >= sizeof(int));
> int foo(float f) {
> return *std::launder(reinterpret_cast<int*>(&f)); }
>
> As it stands, invocation of foo is undefined, as the argument to launder is not pointing to an object of type int (or similar) within its lifetime,
> violating launder's requirement.
>
> launder is designed to inhibit address propagation analysis, which is the only concerning optimization. Moreover, as long as all usual conditions are
> met (alignment, size & trap values), this should be fine on any implementation. If so, can we make the above formally well-defined?
>
> This is not fine. Type-based aliasing analysis (TBAA) is allowed to determine that the write to "f" and the read from the dereference is not related.
> Consider the effects of inlining:
> int main(void) { return !foo(0.5f); }
>
> becomes (loosely):
>
> int main(void) {
> int __ret;
> {
> float __f = 0.5f;
> __ret = *std::launder(reinterpret_cast<int *>(&__f));
> }
> return !__ret;
> }
>
> The implementation is allowed to observe that there are no TBAA-compatible reads of the value of __f within its lifetime.
Isn't the whole idea that launder's definition is, to some extent, intransparent to optimizers? We're passing a pointer to f into launder. As long as
the analyser is told to assume that calls to launder perform what not, it cannot elide the initialization, because launder could read.
Perhaps launder isn't the right function to base such functionality on, anyway (I just had the impression it fitted the picture of an "opaque"
identity function well). Then my question would rather be if it is sensible to provide some function (or language construct), e.g. taking a glvalue
and returning one of a given type, s.t. aliasing via the returned glvalue can be well-defined. I don't think there would be great technical obstacles
in adjusting aliasing analysers to treat such calls accordingly, but it would allow for a concise way of disabling strict aliasing for an operation
while still benefiting from powerful optimization everywhere else.
Robert
> The likely result is that
> the initialization of __f would be optimized away.
>
> -- HT
>
> Being able to use launder in such scenarios would render circumlocutions via memcpy superfluous.
>
> Robert
> _______________________________________________
> ub mailing list
> ub_at_[hidden] <mailto:ub_at_[hidden]>
> http://www.open-std.org/mailman/listinfo/ub
>
>
>
>
> _______________________________________________
> ub mailing list
> ub_at_[hidden]
> http://www.open-std.org/mailman/listinfo/ub
>
> On Fri, Feb 26, 2016 at 7:12 AM, Robert Haberlach <rh633_at_[hidden] <mailto:rh633_at_[hidden]>> wrote:
>
> I apologize in advance if this was discussed before; I didn't check the entire archive. Consider
>
> static_assert(alignof(float) >= alignof(int) && sizeof(float) >= sizeof(int));
> int foo(float f) {
> return *std::launder(reinterpret_cast<int*>(&f)); }
>
> As it stands, invocation of foo is undefined, as the argument to launder is not pointing to an object of type int (or similar) within its lifetime,
> violating launder's requirement.
>
> launder is designed to inhibit address propagation analysis, which is the only concerning optimization. Moreover, as long as all usual conditions are
> met (alignment, size & trap values), this should be fine on any implementation. If so, can we make the above formally well-defined?
>
> This is not fine. Type-based aliasing analysis (TBAA) is allowed to determine that the write to "f" and the read from the dereference is not related.
> Consider the effects of inlining:
> int main(void) { return !foo(0.5f); }
>
> becomes (loosely):
>
> int main(void) {
> int __ret;
> {
> float __f = 0.5f;
> __ret = *std::launder(reinterpret_cast<int *>(&__f));
> }
> return !__ret;
> }
>
> The implementation is allowed to observe that there are no TBAA-compatible reads of the value of __f within its lifetime.
Isn't the whole idea that launder's definition is, to some extent, intransparent to optimizers? We're passing a pointer to f into launder. As long as
the analyser is told to assume that calls to launder perform what not, it cannot elide the initialization, because launder could read.
Perhaps launder isn't the right function to base such functionality on, anyway (I just had the impression it fitted the picture of an "opaque"
identity function well). Then my question would rather be if it is sensible to provide some function (or language construct), e.g. taking a glvalue
and returning one of a given type, s.t. aliasing via the returned glvalue can be well-defined. I don't think there would be great technical obstacles
in adjusting aliasing analysers to treat such calls accordingly, but it would allow for a concise way of disabling strict aliasing for an operation
while still benefiting from powerful optimization everywhere else.
Robert
> The likely result is that
> the initialization of __f would be optimized away.
>
> -- HT
>
> Being able to use launder in such scenarios would render circumlocutions via memcpy superfluous.
>
> Robert
> _______________________________________________
> ub mailing list
> ub_at_[hidden] <mailto:ub_at_[hidden]>
> http://www.open-std.org/mailman/listinfo/ub
>
>
>
>
> _______________________________________________
> ub mailing list
> ub_at_[hidden]
> http://www.open-std.org/mailman/listinfo/ub
>
Received on 2016-02-26 19:04:17