[llvm-dev] problem with moveSpillUsesAfterCoroBegin

Andrew Kelley via llvm-dev
Mon, 26 Feb 2018 06:14:07 -0000

Here's what this function is supposed to do:

// Move early uses of spilled variable after CoroBegin.
// For example, if a parameter had address taken, we may end up with the
code
// like:
//        define @f(i32 %n) {
//          %n.addr = alloca i32
//          store %n, %n.addr
//          ...
//          call @coro.begin
//    we need to move the store after coro.begin


in the implementation it has:

        // TODO: Make this more robust. Currently if we run into a situation
        // where simple instruction move won't work we panic and
        // report_fatal_error.
        for (User *UI : I->users()) {
          if (!DT.dominates(CoroBegin, cast<Instruction>(UI)))
            report_fatal_error("cannot move instruction since its users are
not"
                               " dominated by CoroBegin");
        }

here is what my frontend is currently generating (I'll paste the frontend
code for clarity and then the LLVM IR):

const std = @import("std");

export fn entry() void {
    const p = (async(std.debug.global_allocator) amain()) catch unreachable;
    cancel p;
}

async fn amain() error {
    return error.Failure;
}

; Function Attrs: nobuiltin nounwind
define void @entry() #0 !dbg !220 {
Entry:
  %0 = alloca { i16, i8* }, align 8
  %1 = alloca { i16, i8* }, align 8
  %p = alloca i8*, align 8
  %2 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 0,
!dbg !226
  store i16 0, i16* %2, !dbg !226
  %3 = call fastcc i8* @amain(%Allocator* getelementptr inbounds
(%FixedBufferAllocator, %FixedBufferAllocator* @global_fixed_allocator, i32
0, i32 0), i16* %2), !dbg !226
  %4 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 1,
!dbg !226
  store i8* %3, i8** %4, !dbg !226
  %5 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 0,
!dbg !227
  %6 = load i16, i16* %5, align 2, !dbg !227
  %7 = icmp eq i16 %6, 0, !dbg !227
  br i1 %7, label %UnwrapErrOk, label %UnwrapErrError, !dbg !227

UnwrapErrError:                                   ; preds = %Entry
  tail call fastcc void @__zig_fail_unwrap(%StackTrace* null, i16 %6), !dbg
!227
  unreachable, !dbg !227

UnwrapErrOk:                                      ; preds = %Entry
  %8 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 1,
!dbg !227
  %9 = load i8*, i8** %8, align 8, !dbg !227
  store i8* %9, i8** %p, align 8, !dbg !228
  call void @llvm.dbg.declare(metadata i8** %p, metadata !224, metadata
!DIExpression()), !dbg !228
  %10 = load i8*, i8** %p, align 8, !dbg !229
  call void @llvm.coro.destroy(i8* %10), !dbg !231
  ret void, !dbg !232
}


; Function Attrs: nobuiltin nounwind
define internal fastcc i8* @amain(%StackTrace* nonnull, %Allocator*, i16*)
unnamed_addr #0 !dbg !234 {
Entry:
  %3 = alloca { i16, %"[]u8" }, align 8
  %4 = alloca { i16, %"[]u8" }, align 8
  %_anon = alloca %AsyncFramePromise, align 8
  %5 = bitcast %AsyncFramePromise* %_anon to i8*, !dbg !245
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast
(%AsyncFramePromise* @16 to i8*), i64 24, i32 8, i1 false), !dbg !245
  call void @llvm.dbg.declare(metadata %AsyncFramePromise* %_anon, metadata
!239, metadata !DIExpression()), !dbg !245
  %6 = bitcast %AsyncFramePromise* %_anon to i8*, !dbg !245
  %7 = call token @llvm.coro.id(i32 16, i8* %6, i8* null, i8* null), !dbg
!245
  %8 = call i1 @llvm.coro.alloc(token %7), !dbg !245
  br i1 %8, label %DynAlloc, label %CoroBegin, !dbg !245

DynAlloc:                                         ; preds = %Entry
  %9 = call i64 @llvm.coro.size.i64(), !dbg !245
  %10 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 0,
!dbg !245
  %11 = load void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64,
i29)*, void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)**
%10,
align 8, !dbg !245
  call fastcc void %11({ i16, %"[]u8" }* %3, %StackTrace* %0,
%Allocator*
%1, i64 %9, i29 16), !dbg !245
  %12 = getelementptr inbounds { i16, %"[]u8" }, { i16,
%"[]u8" }* %3, i32
0, i32 0, !dbg !245
  %13 = load i16, i16* %12, align 2, !dbg !245
  %14 = icmp ne i16 %13, 0, !dbg !245
  br i1 %14, label %AllocError, label %AllocOk, !dbg !245

AllocError:                                       ; preds = %DynAlloc
  %15 = getelementptr inbounds { i16, %"[]u8" }, { i16,
%"[]u8" }* %3, i32
0, i32 0, !dbg !245
  %16 = load i16, i16* %15, align 2, !dbg !245
  store i16 %16, i16* %2, !dbg !245
  ret i8* null, !dbg !245

AllocOk:                                          ; preds = %DynAlloc
  %17 = getelementptr inbounds { i16, %"[]u8" }, { i16,
%"[]u8" }* %3, i32
0, i32 1, !dbg !245
  %18 = getelementptr inbounds %"[]u8", %"[]u8"* %17, i32 0,
i32 0, !dbg
!245
  %19 = load i8*, i8** %18, align 8, !dbg !245
  br label %CoroBegin, !dbg !245

CoroBegin:                                        ; preds = %AllocOk, %Entry
  %20 = phi i8* [ null, %Entry ], [ %19, %AllocOk ], !dbg !245
  %21 = phi %"[]u8"* [ undef, %Entry ], [ %17, %AllocOk ], !dbg !245
  %22 = call i8* @llvm.coro.begin(token %7, i8* %20), !dbg !245
  %23 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise*
%_anon, i32 0, i32 0, !dbg !245
  %24 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise*
%_anon, i32 0, i32 1, !dbg !245
  %25 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise*
%_anon, i32 0, i32 2, !dbg !245
  store i16* %24, i16** %25, align 8, !dbg !245
  %26 = load i16*, i16** %25, align 8, !dbg !246
  store i16 2, i16* %26, align 2, !dbg !246
  %27 = load i8*, i8** %23, align 8, !dbg !246
  %28 = icmp ne i8* %27, null, !dbg !246
  br i1 %28, label %CoroNormalFinal, label %CoroEarlyFinal, !dbg !246

CoroEarlyFinal:                                   ; preds = %CoroBegin
  %29 = call i8 @llvm.coro.suspend(token none, i1 true), !dbg !245
  switch i8 %29, label %Suspend [
    i8 0, label %InvalidResume
    i8 1, label %FinalCleanup
  ], !dbg !245

Suspend:                                          ; preds = %CoroEarlyFinal
  %30 = call i1 @llvm.coro.end(i8* null, i1 false), !dbg !245
  ret i8* %22, !dbg !245

InvalidResume:                                    ; preds = %CoroEarlyFinal
  tail call fastcc void @panic(%"[]u8"* @20, %StackTrace* null), !dbg
!245
  unreachable, !dbg !245

CoroNormalFinal:                                  ; preds = %CoroBegin
  br label %CheckFree, !dbg !245

FinalCleanup:                                     ; preds = %CoroEarlyFinal
  %31 = load i16*, i16** %25, align 8, !dbg !245
  %32 = bitcast i16* %31 to i8*, !dbg !245
  %33 = bitcast i16* %24 to i8*, !dbg !245
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %32, i8* %33, i64 2, i32 2, i1
false), !dbg !245
  br label %CheckFree, !dbg !245

CheckFree:                                        ; preds = %FinalCleanup,
%CoroNormalFinal
  %34 = phi i1 [ false, %FinalCleanup ], [ true, %CoroNormalFinal ], !dbg
!245
  br i1 %8, label %DynFree, label %EndFree, !dbg !245

DynFree:                                          ; preds = %CheckFree
  %35 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 2,
!dbg !245
  %36 = load void (%Allocator*, %"[]u8"*)*, void (%Allocator*,
%"[]u8"*)**
%35, align 8, !dbg !245
  call fastcc void %36(%Allocator* %1, %"[]u8"* byval %21), !dbg !245
  br label %EndFree, !dbg !245

EndFree:                                          ; preds = %DynFree,
%CheckFree
  br i1 %34, label %Resume, label %Return, !dbg !245

Resume:                                           ; preds = %EndFree
  %37 = load i8*, i8** %23, align 8, !dbg !245
  %38 = load i8*, i8** %23, align 8, !dbg !245
  call void @llvm.coro.resume(i8* %38), !dbg !245
  br label %Return, !dbg !245

Return:                                           ; preds = %Resume,
%EndFree
  ret i8* undef, !dbg !245
}


This triggers:

"cannot move instruction since its users are not dominated by
CoroBegin"

When I use gdb to print I->dump():

  %8 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 0,
!dbg !71


Much to my surprise, this is pointing to an instruction in the `entry`
function, not the `amain` coroutine function. Is this a bug?

Thanks for the help,
Andrew
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20180226/4fde8c27/attachment.html>