0

I'm having trouble understanding the memory allocations made by C++20 coroutines. For my code, I would like to verify that the compiler is eliding heap allocations, and if it isn't, to find out what data is being placed within that allocation. My strategy right now has been to inspect the assembly output, but I'm not sure what to look for.

How can I verify that heap allocations are elided?

Edit

A possible example to refer to would be Lewis Baker's code here: https://www.godbolt.org/z/EoovEEKvW

Respondents should feel free to refer to other code or libraries if they like.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Mark Wallace
  • 528
  • 2
  • 12
  • 1
    "*if it isn't, to find out what data is being placed within that allocation*" What would that matter? It's not like you can change it. – Nicol Bolas Aug 22 '22 at 21:24
  • "It's not like you can change it." Why not? Coroutines are still finnicky, and small changes to code can make the difference in whether or not the compiler performs certain optimizations. This is C++. If the compiler can't do it, I'm sure I can find a way to do it myself. – Mark Wallace Aug 22 '22 at 21:34
  • 2
    Add your own `operator new` and see if it's called? – HolyBlackCat Aug 22 '22 at 21:34
  • 1
    @MarkWallace: "*small changes to code can make the difference in whether or not the compiler performs certain optimizations*" That's not how coroutine elision works. The primary determining factor with regard to elision is how the coroutine gets *used*, not how it gets *defined*. If the compiler doesn't elide to coroutine, changing what goes into it won't help. – Nicol Bolas Aug 22 '22 at 21:41
  • 1
    @MarkWallace: "*If the compiler can't do it, I'm sure I can find a way to do it myself.*" That's *also* not how coroutines work. It's the compiler that generates all of the boilerplate for them. Now sure, you can write your own continuation functions that have their own boilerplate. But you could have done that before. – Nicol Bolas Aug 22 '22 at 21:43
  • "The primary determining factor with regard to elision is how the coroutine gets used, not how it gets defined." Then I'll see if I can change how the coroutine is used... – Mark Wallace Aug 22 '22 at 21:46
  • @MarkWallace: Broadly speaking, if you can change how it's being used, then you probably aren't in a position to get elision. The standard case for elision is generators. Passing coroutines around is one of the main things that shuts off elision, so if you were doing that with a generator, it was probably because you needed to. So I'm not sure how you could adjust your code accordingly. – Nicol Bolas Aug 22 '22 at 22:11

1 Answers1

0

The simplest thing you could do is give your promise type allocator/deallocator functions (ie: operator new/delete members). These functions are called to allocate storage for the coroutine if such storage is needed. As such, if they are not called for a particular use of a coroutine, storage was not needed.

However, this is not a guarantee. It is entirely possible that implementations will bypass elision if you provide such allocators. After all, your program might rely on having a short stack, so if you use allocators, they may be allocating from static storage instead of the actual program stack.

Then again, maybe not. The most you can do is try it and see what happens.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982