jinhuang1102 wrote:

> I'd put the explanation from 
> [here](https://github.com/llvm/llvm-project/issues/185949#issuecomment-4703198841)
>  in the commit message. IMHO the way `resume` is handled is the important 
> thing (for performance), and how that's handled deserves focus, rather than a 
> side-note.
> 
> Can you also add an explanation as to why the 3 places 
> (Coro{Split|Frame|Cleanup}) cover profile propagation for coroutines - or is 
> there anything major left after this? I.e. it's less interesting that 3 files 
> got patched (since one can just read the diff), and more interesting as to 
> how the overall change addresses the overall problem (==profile propagation 
> for coroutines) - since that's design information not immediately apparent 
> from the change itself, and, thus, worth communicating.

Thanks for the comment!  You are right that explaining the design of profile 
propagation is much more valuable than just listing the changes files.

The PGO profiles propagation is mainly happened in 
`SwitchCoroutineSplitter::split`. Let's look at how the IR is transformed in 
the 1) `createResumeEntryBlock(F, Shape);` and 2) the creation of `ResumeClone` 
(`.resume`). 

We use 
[coro-await-suspend-lower-invoke.ll](https://github.com/llvm/llvm-project/blob/main/llvm/test/Transforms/Coroutines/coro-await-suspend-lower-invoke.ll)
 in the following discussion.

1. The `createResumeEntryBlock` prepares the coroutine's control flow for 
splitting by setting up a unified resume dispatch block (`resume.entry`) and 
refactoring the suspend points. 
a. Adding the Resume Dispatcher:
It appends the `resume.entry` block at the end of the original function `f`. 
This block loads the suspend index from the coroutine frame and dispatches 
control flow to the resume points:
    ```
    define void @f() personality i32 0 !prof !0 {
    ...
    resume.entry:                                     ; No predecessors!
      %index.addr = getelementptr inbounds i8, ptr %hdl, i64 16
      %index = load i2, ptr %index.addr, align 1
      switch i2 %index, label %unreachable [
        i2 0, label %resume.0
        i2 1, label %resume.1
        i2 -2, label %resume.2
        i2 -1, label %resume.3
      ], !prof !3
    
    unreachable:                                      ; preds = %resume.entry
      unreachable
    }
    ```
b. Before the splitting, a typical suspend point looks like this:
  ```
    CoroSave:
      %0 = call token @llvm.coro.save(ptr %hdl)
      br label %CoroSuspend
    CoroSuspend:
      %suspend.init = call i8 @llvm.coro.suspend(token %0, i1 false)
      br label %AfterCoroSuspend
    AfterCoroSuspend:
      switch i8 %suspend.init, label %ret [
        i8 0, label %CoroSave1
        i8 1, label %cleanup
      ]
  ```
`createResumeEntryBlock` refactors this into a landing BB to unify the suspend 
path(initial execution) and resume path when resume() is called:
  ```
  CoroSave:
    %index.addr12 = getelementptr inbounds i8, ptr %hdl, i64 16
    store i2 0, ptr %index.addr12, align 1          ; Save the index (0) before 
suspending
    br label %CoroSuspend
  
  CoroSuspend:
    br label %resume.0.landing                      ; Jump to landing pad to 
return -1
  
  resume.0:                                         ; Target of the dispatch 
switch
    %suspend.init = call i8 @llvm.coro.suspend(token none, i1 false)
    br label %resume.0.landing
  
  resume.0.landing:
    ; PHI merges: -1 (from suspension path) vs. %suspend.init (from resumption 
path)
    %0 = phi i8 [ -1, %CoroSuspend ], [ %suspend.init, %resume.0 ]
    br label %AfterCoroSuspend
  
  AfterCoroSuspend:
    switch i8 %0, label %ret [
      i8 0, label %CoroSave1
      i8 1, label %cleanup
    ]
  ```

(1/n - More to come in the next comment)

https://github.com/llvm/llvm-project/pull/184466
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to