[llvm-dev] Asking for advice: how to best place the CoroSplit pass

Xun Li via llvm-dev llvm-dev at lists.llvm.org
Thu Jan 28 11:17:19 PST 2021


The current way of scheduling CoroSplit pass is not ideal, and in some
cases can lead to significant slowdown of the compiler.
I would like to ask for advice/feedback on what might be the best way
to structure the passes so that CoroSplit pass is put in the right
place. First of all, let me explain the current situation:

CoroSplit pass is a pass that splits a coroutine function into
multiple functions, in order to implement the semantics of coroutines.
Right now, CoroSplit pass is added in the InlinerPipeline, right after
the Inliner pass (PassBuilder::buildInlinerPipeline). So it looks like
- ModuleInlinerWrapperPass
    - A few global analysis
    - CGSCCPipeline
        - Inliner
        - CoroSplitPass
        - FunctionSimplificationPipeline

It's important to note that when the first time a coroutine function
goes through CoroSplitPass, it will not be split. Instead, it will
just add its belonging SCC back to the pipeline and hence repeat the
entire CGSCC pipeline. The goal for doing so is to allow coroutines to
be optimized twice, first time before splitting, so that it can have
smaller frame size, and second time after splitting, so that the
splitted functions can get cleaned up.
Furthermore, CoroSplitPass needs to be in CGSCC pipeline in order to
enable coroutine elision (an important coroutine optimization to
reduce dynamic memory allocation), that is, we want to walk through
SCCs postorder so that functions can inline fully processed coroutines
and does CoroElision.
A side-effect of this structure, however, is that all the
non-coroutines that are in the same SCC of any coroutine will run
through Inliner twice. This can lead to unexpected slowdown if an
aggressive inlining threshold is used and generates unexpectedly large
functions. There is also not much benefit for coroutines to run
through Inliner pass twice either.

So the ideal goal looks like this:
For coroutine functions, run through:
  Inliner -> function simplification passes -> CoroSplit -> function
simplification passes
For non-coroutine functions, just run through as usual:
  Inliner -> function simplification passes.

The challenge is of course when they are in the same SCC it's hard to
separate them like this. Any thoughts on how we might be able to
achieve that?


More information about the llvm-dev mailing list