I recently looked at the C++ standard for coroutine use, and IMO the people who developed that standard did not understand what coroutines should be.
Subroutines are implemented with a stack of activation records. Coroutines do not generate an activation record, but they do have local data. Therefore, the C++20 standard has created a coroutine thing that should not exist IMO. It puts an activation record on the heap and suspends execution to go to another piece of code. I believe that is a guess at what coroutines were initially created to be due to an effort to implement what http://home.claranet.nl/users/mhx/Forth_Bell.pdf described. Bell’s description IMO was ment to impress his contemporaries but he did a poor job. Bell described the activation record in terms that were contemporary. Compilers were still in their adolescent years, and this might have been a reasonable attempt to describe coroutines in those contemporary terms.
In my opinion, we should go back and study coroutines in an application that actually uses them correctly before we try to reintroduce them. Moving Forth: Part 1 (see: The Threading Technique) This is a use of coroutines the way they were originally designed.
To describe coroutines to an LLVM savy audience, I would simply say a coroutine is subordinate to a subroutine (function). The IR for a subroutine contains Basic Blocks (BBs) that are separated by flow of control (FoC) actions. A Region of BBs always has one entry point. A coroutine is simply a BB or a BB Region subordinate to a subroutine. It has an entry point name and can jump on exit to any other coroutine that is subordinate to the same parent subroutine or it can exit the parent subroutine. The coroutine is “called” by a coroutine jump rather than a subroutine call. I am going to call the coroutine jump “goco” which means “goto coroutine.” Therefore, all BB Regions of the parent subroutine after the entry block could be coroutines. All F0C between coroutines using the goco instruction must be to coroutines subordinate of the same parent subroutine. Any use of a “return” statement will exit the coroutine and the parent subroutine.
The activation record is associated with the parent subroutine. The set of coroutines under that parent, all use the parent subourtine’s activation record. A coroutine is only visible to be called by the parent subroutine and coroutines within the set of couroutines under that parent subroutine.
Although coroutines do not usually have arguments, an argument list could be added to assign values like phi functions.
All of the above coroutine rules follow directly from the concept that a coroutine is a BB (or a Region of BBs) of a parent suboutine.
LLVM should provide a capability to create a set of coroutines within a subroutine that can mutually jump to other coroutines within the same set under the same parent subroutine.