[PATCH] D97915: [Coroutines] Handle overaligned frame allocation

Yuanfang Chen via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 29 11:53:43 PDT 2021


ychen added a comment.

For coroutine `f0` in `test/CodeGenCoroutines/coro-alloc.cpp`

The allocation looks like this:

  ; Function Attrs: noinline nounwind optnone mustprogress
  define dso_local void @f0() #0 {
  entry:
    %0 = alloca %struct.global_new_delete_tag, align 1
    %1 = alloca %struct.global_new_delete_tag, align 1
    %__promise = alloca %"struct.std::experimental::coroutine_traits<void, global_new_delete_tag>::promise_type", align 1
    %ref.tmp = alloca %struct.suspend_always, align 1
    %undef.agg.tmp = alloca %struct.suspend_always, align 1
    %agg.tmp = alloca %"struct.std::experimental::coroutine_handle", align 1
    %agg.tmp2 = alloca %"struct.std::experimental::coroutine_handle.0", align 1
    %undef.agg.tmp3 = alloca %"struct.std::experimental::coroutine_handle.0", align 1
    %ref.tmp4 = alloca %struct.suspend_always, align 1
    %undef.agg.tmp5 = alloca %struct.suspend_always, align 1
    %agg.tmp7 = alloca %"struct.std::experimental::coroutine_handle", align 1
    %agg.tmp8 = alloca %"struct.std::experimental::coroutine_handle.0", align 1
    %undef.agg.tmp9 = alloca %"struct.std::experimental::coroutine_handle.0", align 1
    %2 = bitcast %"struct.std::experimental::coroutine_traits<void, global_new_delete_tag>::promise_type"* %__promise to i8*
    %3 = call token @llvm.coro.id(i32 16, i8* %2, i8* null, i8* null)
    %4 = call i1 @llvm.coro.alloc(token %3)
    br i1 %4, label %coro.alloc, label %coro.init
  
  coro.alloc:                                       ; preds = %entry
    %5 = call i64 @llvm.coro.size.i64()
    %6 = call i64 @llvm.coro.align.i64()
    %7 = sub nsw i64 %6, 16
    %8 = icmp sgt i64 %7, 0
    %9 = select i1 %8, i64 %7, i64 0
    %10 = add i64 %5, %9
    %call = call noalias nonnull i8* @_Znwm(i64 %10) #11
    br label %coro.check.align
  
  coro.check.align:                                 ; preds = %coro.alloc
    %11 = call i64 @llvm.coro.align.i64()
    %12 = icmp ugt i64 %11, 16
    br i1 %12, label %coro.alloc.align, label %coro.init
  
  coro.alloc.align:                                 ; preds = %coro.check.align
    %mask = sub i64 %11, 1
    %intptr = ptrtoint i8* %call to i64
    %over_boundary = add i64 %intptr, %mask
    %inverted_mask = xor i64 %mask, -1
    %aligned_intptr = and i64 %over_boundary, %inverted_mask
    %diff = sub i64 %aligned_intptr, %intptr
    %aligned_result = getelementptr inbounds i8, i8* %call, i64 %diff
    call void @llvm.assume(i1 true) [ "align"(i8* %aligned_result, i64 %11) ]
    %13 = call i32 @llvm.coro.raw.frame.ptr.offset.i32()
    %14 = getelementptr inbounds i8, i8* %aligned_result, i32 %13
    %15 = bitcast i8* %14 to i8**
    store i8* %call, i8** %15, align 8
    br label %coro.init
  
  coro.init:                                        ; preds = %coro.alloc.align, %coro.check.align, %entry
    %16 = phi i8* [ null, %entry ], [ %call, %coro.check.align ], [ %aligned_result, %coro.alloc.align ]
    %17 = call i8* @llvm.coro.begin(token %3, i8* %16)
    call void @_ZNSt12experimental16coroutine_traitsIJv21global_new_delete_tagEE12promise_type17get_return_objectEv(%"struct.std::experimental::coroutine_traits<void, global_new_delete_tag>::promise_type"* nonnull dereferenceable(1) %__promise)
    call void @_ZNSt12experimental16coroutine_traitsIJv21global_new_delete_tagEE12promise_type15initial_suspendEv(%"struct.std::experimental::coroutine_traits<void, global_new_delete_tag>::promise_type"* nonnull dereferenceable(1) %__promise)
    %call1 = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* nonnull dereferenceable(1) %ref.tmp) #2
    br i1 %call1, label %init.ready, label %init.suspend

The deallocation looks like this:

  cleanup:                                          ; preds = %final.ready, %final.cleanup, %init.cleanup
    %cleanup.dest.slot.0 = phi i32 [ 0, %final.ready ], [ 2, %final.cleanup ], [ 2, %init.cleanup ]
    %22 = call i8* @llvm.coro.free(token %3, i8* %17)
    %23 = icmp ne i8* %22, null
    br i1 %23, label %coro.free, label %after.coro.free
  
  coro.free:                                        ; preds = %cleanup
    %24 = call i64 @llvm.coro.align.i64()
    %25 = icmp ugt i64 %24, 16
    %26 = call i32 @llvm.coro.raw.frame.ptr.offset.i32()
    %27 = getelementptr inbounds i8, i8* %22, i32 %26
    %28 = bitcast i8* %27 to i8**
    %29 = load i8*, i8** %28, align 8
    %30 = select i1 %25, i8* %29, i8* %22
    call void @_ZdlPv(i8* %30) #2
    br label %after.coro.free
  
  after.coro.free:                                  ; preds = %cleanup, %coro.free
    switch i32 %cleanup.dest.slot.0, label %unreachable [
      i32 0, label %cleanup.cont
      i32 2, label %coro.ret
    ]
  
  cleanup.cont:                                     ; preds = %after.coro.free
    br label %coro.ret
  
  coro.ret:                                         ; preds = %cleanup.cont, %after.coro.free, %final.suspend, %init.suspend
    %31 = call i1 @llvm.coro.end(i8* null, i1 false)
    ret void
  
  unreachable:                                      ; preds = %after.coro.free
    unreachable
  }


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97915



More information about the llvm-commits mailing list