[cfe-dev] Smart Pointer Lifetime Optimizations

<Alexander G. Riccio> via cfe-dev cfe-dev at lists.llvm.org
Sat Jun 13 19:25:37 PDT 2020


Can I chime in way after the fact? I *think* the move = bitcopies (P1029R3
by Niall Douglas) might help a lot with simplifying this problem, by
allowing for a much simpler lifetime analysis when the smart pointer is
moved around via std::move explicitly or when it's otherwise moved around
implicitly (return values, etc).

If you read the proposal, he mentions the trivial_abi attribute, and
explicitly mentions unique_ptr. He's a smart guy.

Obviously, that's a language solution, not a clang solution, but it seems
more worthy of someone's time to implement the general solution than to
implement a use-specific optimization pass.


On Fri, Jun 5, 2020, 2:46 PM Zoe Carver via cfe-dev <cfe-dev at lists.llvm.org>
wrote:

> Hello all,
>
>
> I'm planning to do some work to add lifetime optimization passes for smart
> pointers and reference-counted objects. I'll use this email as a sort of
> proposal for what I hope to do.
>
>
> *Scope*
>
>
> As I'm developing the pass, I'm trying to keep it general and create
> utilities that could work across multiple smart pointers. But, right now,
> I'm focussing on unique_ptr and applying specific ownership optimizations
> to unique_ptr only.
>
>
> *unique_ptr Optimzations*
>
>
> The pass I'm currently developing adds a single, simple, optimization:
> constant fold the destructor based on ownership information. unique_ptr
> has a lot of ownership information communicated with reference semantics.
> When a unique_ptr is moved into another function, that function takes
> over ownership of the unique_ptr, and subsequent destructors can be
> eliminated (because they will be no-ops). Otherwise, branchless functions
> are often complicated after inlining unique_ptr's destructor so, this
> optimization should be fairly beneficial.
>
>
> unique_ptr's reset and release methods both complicate this optimization
> a bit. Because they are also able to transfer and remove ownership, all
> unknown instructions must be ignored. However, in the future, knowledge of
> those methods might be able to make the pass more robust.
>
>
> With unique_ptr, it's difficult to prove liveness. So, it is hard to
> constant fold the destructor call to always be there. Maybe in the future,
> this would be possible, though (with sufficient analysis).
>
>
> Last, an optimization that I hope to do is lowering the unique_ptr to a
> raw pointer if all lifetime paths are known. I think removing this layer of
> abstraction would make it easier for other optimization passes to be
> successful. Eventually, we may even be able to specialize functions that
> used to take a unique_ptr to now take a raw pointer, if the argument's
> lifetime was also able to be fully analyzed.
>
>
> *Lifetime Annotations*
>
>
> Right now, the pass relies on (pre-inlined) function calls to generate
> ownership information. Another approach would be to add ownership
> annotations, such as the lifetime intrinsics (i.e. llvm.lifetime.start).
>
>
> *ARC Optimizations*
>
>
> There are a huge number of large and small ARC optimizations already in
> LLVM. For unique_ptr specifically, I'm not sure these are of any benefit
> because unique_ptr doesn't actually do any reference counting. But, later
> on, when I start working on generalizing this pass to support more smart
> pointers (specifically shared_ptr) I think the ARC optimization pass, and
> especially the utilities it contains, could be very beneficial. If anyone
> has experience with ARC optimizations, I'd love to hear your thoughts on
> extending them to other reference counted objects.
>
>
> *trivial_abi and Hidden References*
>
>
> Arthur O'Dwyer made a good point, which is that a lot of these
> optimizations can be applied when with the trivial_abi attribute.
> However, given that's not a standard attribute and these optimizations only
> *happen* to work with trivial_abi (i.e., in a more complicated program,
> they may not continue to work). I think lifetime utilities and specific
> lifetime optimization passes are still beneficial (especially if they can
> be applied to other smart pointers in the future).
>
>
> Because all smart pointers have non-trivial destructors, they are always
> passed by hidden references. With unique_ptr, this is as simple as
> bit-casting the pointer member to unique_ptr, which would allow for it to
> be lowered to a single raw pointer instead of a stack-allocated object.
> Even without the trival_abi attribute, I think this is an optimization
> that could be done.
>
>
> *Results*
>
>
> Here's the unique_ptr pass I've been talking about: ⚙ D81288 Opt Smart
> pointer lifetime optimizations pass. <https://reviews.llvm.org/D81288>
>
> For reference, here are the before and after results:
>
> Clang trunk (four branches): Compiler Explorer
> <https://godbolt.org/z/bsJFty>
>
> With optimizations (branchless): https://pastebin.com/raw/mQ2r6pru
>
>
> Best,
>
> Zoe
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200613/3355cbd7/attachment-0001.html>


More information about the cfe-dev mailing list