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
