[llvm-dev] RFC: Coroutine Optimization Passes

Gor Nishanov via llvm-dev llvm-dev at lists.llvm.org
Thu Jul 14 21:28:02 PDT 2016


Hi David:

>> How do you deal with basic blocks which appear to be used by multiple parts
>> of the coroutine? We handled this in WinEHPrepare by cloning any BBs which
>> were shared.

I experimented with several approaches, but, cloning ended up being the simplest
and most reliable. Suspend points express three different control flows that
can happen at the suspend point: a suspension (default), resumption (0) and
destruction (1).

  %0 = call i8 @llvm.coro.suspend([..])
  switch i8 %0, label %suspend [i8 0, label %resume,
                                i8 1, label %destroy]

I slap a switch that jumps to all suspend points in the function. Then I clone
the function twice (one will become resume clone, and another destroy clone).
This switch becomes the entry block in the clones. Then, I RAUW coro.suspends
with -1, 0, or 1 (in original, resume and destroy clones respectively) and let
SimplifyCFG do the rest. (This is slightly simplified explanation, but it should
 give the idea).

>> I would remove the attribute.  There are all sorts of tricks you can do to
>> avoid scanning the function for calls to the intrinsic.  For example, you
>> can see if a declaration of your intrinsic exists and, if so, if it has an
>> users in the function in question (under the assumption that there are few).

Aye-aye. Will remove the attribute.

With respect to lessening the impact of coroutine passes, one approach I tried
was to look during doInitialize whether there are any uses of coroutine
intrinsics and set a flag if there are any, or maybe build a set of functions
with coroutines intrinsics in doInitialize, so that in runOnFunction, I can just
check whether the function is in the set and skip if it is not.

Then, I scared myself silly that some optimization passes can materialize
new functions or new function bodies and I will miss them. So I stopped doing
that.

I think your approach takes care of my "materialization" concern. (BTW, I don't
even know if that is a real concern). But may not be profitable if there are a
lot of small functions that are faster to scan for coroutine intrinsics then to
scan potentially longer list of coroutine intrinsics users.

BTW, Do you have a preference on how to restart CGSCC pipeline? One of the four
options I listed (repeated in P.S), or even some better way I did not think
about?

Thank you,
Gor

P.S.

Option 1: https://reviews.llvm.org/D21569 (no longer relevant, since we are
                                           removing AttrKind::Coroutine)
Option 2: https://reviews.llvm.org/D21570 (bool& Devirt in runSCC)
Option 3: https://reviews.llvm.org/D21572 (virtual bool restatedRequested())
Option 4: Fake devirtualized call in a function pass, so that RefreshSCC will
          detect devirtualization and restart the pipeline by itself.


More information about the llvm-dev mailing list