[PATCH] D124418: [CHR] Skip region containing llvm.coro.id

Wei Wang via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 26 13:53:22 PDT 2022


weiwang added a comment.

In D124418#3473558 <https://reviews.llvm.org/D124418#3473558>, @ChuanqiXu wrote:

> Hi, could you elaborate more what CHR does and why we need to skip coro.id? I don't know what happened now

Sure. We encountered this in one internal workload.

The ICE is trigged by an invalid cast at https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Coroutines/Coroutines.cpp#L231

  void coro::Shape::buildFrom(Function &F) {
    ... ...
    case Intrinsic::coro_begin: {
      auto Id = dyn_cast<CoroIdInst>(CB->getId());
    ... ...

The first argument of `llvm.coro.begin` intrinsic is expected to be `llvm.coro.id`, but it was actually a PHI node.

In fact, if IR verifier is turned on, the compilation would hit an assert after CHR pass (https://github.com/llvm/llvm-project/blob/main/llvm/lib/IR/Verifier.cpp#L3119)

A typical coroutine body has the following control flow

  entry:
    %id = call token @llvm.coro.id(...)
    %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
    br i1 %need.dyn.alloc, label %coro.alloc, label %coro.init
  
  coro.alloc:
    %alloc = call i8* @custom_allocator(...)
    br label %coro.init
  
  coro.init:
    %phi = phi i8* [ null, %entry ], [ %alloc, %coro.alloc ]
    %hdl = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %phi)
  ... ...

This forms a region of 2 blocks `entry` and `coro.alloc` and with `coro.init` being the exit block.

It is possible that after `CoroSplit` pass, coroutine functions are inlined into other functions. And during subsequent `CHR` pass, when the blocks in such region are cloned, the control flow becomes

  ... ...
  entry:
    %id = call token @llvm.coro.id(...)
    %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
    br i1 %need.dyn.alloc, label %coro.alloc, label %coro.init
  
  coro.alloc:
    %alloc = call i8* @custom_allocator(...)
    br label %coro.init
  
  ; clone of entry (cold path)
  entry.nonchr:
    %id.nonchr = call token @llvm.coro.id(...)
    %need.dyn.alloc.nonchr = call i1 @llvm.coro.alloc(token %id)
    br i1 %need.dyn.alloc.nonchr, label %coro.alloc.nonchr, label %coro.init
  
  ; clone of coro.alloc (cold path)
  coro.alloc.nonchr:
    %alloc.nonchr = call i8* @custom_allocator(...)
    br label %coro.init
  
  coro.init:
    %phi.id = phi token [%id, %entry], [%id, %cor.alloc], [%id.nonchr, %entry.nonchr], [%id.nonchr, %coro.alloc.nonchr]
    %phi.alloc = phi i8* [ null, %entry ], [ %alloc, %coro.alloc ], [ null, %entry.nonchr ], [ %alloc.nonchr, %coro.alloc.nonchr ]
    %hdl = call noalias nonnull i8* @llvm.coro.begin(token %phi.id, i8* %phi.alloc)
    ... ...

This creates an invalid PHI node with token type at the beginning of `coro.init` block.

The proposed fix checks for `llvm.coro.id` inside region, and if it is found, the region will be excluded from CHR. This way the `entry` block will not be cloned, and thus no PHI node will be created.

This could lead to less optimal codegen though, because the region is excluded, it can prevent CHR from merging adjacent regions into bigger scope and hoisting more branches.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124418/new/

https://reviews.llvm.org/D124418



More information about the llvm-commits mailing list