<div dir="ltr"><div><div><div><div><div><div>Here's what this function is supposed to do:<br><br>// Move early uses of spilled variable after CoroBegin.<br>// For example, if a parameter had address taken, we may end up with the code<br>// like:<br>//        define @f(i32 %n) {<br>//          %n.addr = alloca i32<br>//          store %n, %n.addr<br>//          ...<br>//          call @coro.begin<br>//    we need to move the store after coro.begin<br><br><br></div>in the implementation it has:<br><br>        // TODO: Make this more robust. Currently if we run into a situation<br>        // where simple instruction move won't work we panic and<br>        // report_fatal_error.<br>        for (User *UI : I->users()) {<br>          if (!DT.dominates(CoroBegin, cast<Instruction>(UI)))<br>            report_fatal_error("cannot move instruction since its users are not"<br>                               " dominated by CoroBegin");<br>        }<br><br></div>here is what my frontend is currently generating (I'll paste the frontend code for clarity and then the LLVM IR):<br><br>const std = @import("std");<br><br>export fn entry() void {<br>    const p = (async(std.debug.global_allocator) amain()) catch unreachable;<br>    cancel p;<br>}<br><br>async fn amain() error {<br>    return error.Failure;<br>}<br><br>; Function Attrs: nobuiltin nounwind<br>define void @entry() #0 !dbg !220 {<br>Entry:<br>  %0 = alloca { i16, i8* }, align 8<br>  %1 = alloca { i16, i8* }, align 8<br>  %p = alloca i8*, align 8<br>  %2 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 0, !dbg !226<br>  store i16 0, i16* %2, !dbg !226<br>  %3 = call fastcc i8* @amain(%Allocator* getelementptr inbounds (%FixedBufferAllocator, %FixedBufferAllocator* @global_fixed_allocator, i32 0, i32 0), i16* %2), !dbg !226<br>  %4 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 1, !dbg !226<br>  store i8* %3, i8** %4, !dbg !226<br>  %5 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 0, !dbg !227<br>  %6 = load i16, i16* %5, align 2, !dbg !227<br>  %7 = icmp eq i16 %6, 0, !dbg !227<br>  br i1 %7, label %UnwrapErrOk, label %UnwrapErrError, !dbg !227<br><br>UnwrapErrError:                                   ; preds = %Entry<br>  tail call fastcc void @__zig_fail_unwrap(%StackTrace* null, i16 %6), !dbg !227<br>  unreachable, !dbg !227<br><br>UnwrapErrOk:                                      ; preds = %Entry<br>  %8 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 1, !dbg !227<br>  %9 = load i8*, i8** %8, align 8, !dbg !227<br>  store i8* %9, i8** %p, align 8, !dbg !228<br>  call void @llvm.dbg.declare(metadata i8** %p, metadata !224, metadata !DIExpression()), !dbg !228<br>  %10 = load i8*, i8** %p, align 8, !dbg !229<br>  call void @llvm.coro.destroy(i8* %10), !dbg !231<br>  ret void, !dbg !232<br>}<br><br><br>; Function Attrs: nobuiltin nounwind<br>define internal fastcc i8* @amain(%StackTrace* nonnull, %Allocator*, i16*) unnamed_addr #0 !dbg !234 {<br>Entry:<br>  %3 = alloca { i16, %"[]u8" }, align 8<br>  %4 = alloca { i16, %"[]u8" }, align 8<br>  %_anon = alloca %AsyncFramePromise, align 8<br>  %5 = bitcast %AsyncFramePromise* %_anon to i8*, !dbg !245<br>  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast (%AsyncFramePromise* @16 to i8*), i64 24, i32 8, i1 false), !dbg !245<br>  call void @llvm.dbg.declare(metadata %AsyncFramePromise* %_anon, metadata !239, metadata !DIExpression()), !dbg !245<br>  %6 = bitcast %AsyncFramePromise* %_anon to i8*, !dbg !245<br>  %7 = call token @<a href="http://llvm.coro.id">llvm.coro.id</a>(i32 16, i8* %6, i8* null, i8* null), !dbg !245<br>  %8 = call i1 @llvm.coro.alloc(token %7), !dbg !245<br>  br i1 %8, label %DynAlloc, label %CoroBegin, !dbg !245<br><br>DynAlloc:                                         ; preds = %Entry<br>  %9 = call i64 @llvm.coro.size.i64(), !dbg !245<br>  %10 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 0, !dbg !245<br>  %11 = load void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)*, void ({ i16, %"[]u8" }*, %StackTrace*, %Allocator*, i64, i29)** %10, align 8, !dbg !245<br>  call fastcc void %11({ i16, %"[]u8" }* %3, %StackTrace* %0, %Allocator* %1, i64 %9, i29 16), !dbg !245<br>  %12 = getelementptr inbounds { i16, %"[]u8" }, { i16, %"[]u8" }* %3, i32 0, i32 0, !dbg !245<br>  %13 = load i16, i16* %12, align 2, !dbg !245<br>  %14 = icmp ne i16 %13, 0, !dbg !245<br>  br i1 %14, label %AllocError, label %AllocOk, !dbg !245<br><br>AllocError:                                       ; preds = %DynAlloc<br>  %15 = getelementptr inbounds { i16, %"[]u8" }, { i16, %"[]u8" }* %3, i32 0, i32 0, !dbg !245<br>  %16 = load i16, i16* %15, align 2, !dbg !245<br>  store i16 %16, i16* %2, !dbg !245<br>  ret i8* null, !dbg !245<br><br>AllocOk:                                          ; preds = %DynAlloc<br>  %17 = getelementptr inbounds { i16, %"[]u8" }, { i16, %"[]u8" }* %3, i32 0, i32 1, !dbg !245<br>  %18 = getelementptr inbounds %"[]u8", %"[]u8"* %17, i32 0, i32 0, !dbg !245<br>  %19 = load i8*, i8** %18, align 8, !dbg !245<br>  br label %CoroBegin, !dbg !245<br><br>CoroBegin:                                        ; preds = %AllocOk, %Entry<br>  %20 = phi i8* [ null, %Entry ], [ %19, %AllocOk ], !dbg !245<br>  %21 = phi %"[]u8"* [ undef, %Entry ], [ %17, %AllocOk ], !dbg !245<br>  %22 = call i8* @llvm.coro.begin(token %7, i8* %20), !dbg !245<br>  %23 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise* %_anon, i32 0, i32 0, !dbg !245<br>  %24 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise* %_anon, i32 0, i32 1, !dbg !245<br>  %25 = getelementptr inbounds %AsyncFramePromise, %AsyncFramePromise* %_anon, i32 0, i32 2, !dbg !245<br>  store i16* %24, i16** %25, align 8, !dbg !245<br>  %26 = load i16*, i16** %25, align 8, !dbg !246<br>  store i16 2, i16* %26, align 2, !dbg !246<br>  %27 = load i8*, i8** %23, align 8, !dbg !246<br>  %28 = icmp ne i8* %27, null, !dbg !246<br>  br i1 %28, label %CoroNormalFinal, label %CoroEarlyFinal, !dbg !246<br><br>CoroEarlyFinal:                                   ; preds = %CoroBegin<br>  %29 = call i8 @llvm.coro.suspend(token none, i1 true), !dbg !245<br>  switch i8 %29, label %Suspend [<br>    i8 0, label %InvalidResume<br>    i8 1, label %FinalCleanup<br>  ], !dbg !245<br><br>Suspend:                                          ; preds = %CoroEarlyFinal<br>  %30 = call i1 @llvm.coro.end(i8* null, i1 false), !dbg !245<br>  ret i8* %22, !dbg !245<br><br>InvalidResume:                                    ; preds = %CoroEarlyFinal<br>  tail call fastcc void @panic(%"[]u8"* @20, %StackTrace* null), !dbg !245<br>  unreachable, !dbg !245<br><br>CoroNormalFinal:                                  ; preds = %CoroBegin<br>  br label %CheckFree, !dbg !245<br><br>FinalCleanup:                                     ; preds = %CoroEarlyFinal<br>  %31 = load i16*, i16** %25, align 8, !dbg !245<br>  %32 = bitcast i16* %31 to i8*, !dbg !245<br>  %33 = bitcast i16* %24 to i8*, !dbg !245<br>  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %32, i8* %33, i64 2, i32 2, i1 false), !dbg !245<br>  br label %CheckFree, !dbg !245<br><br>CheckFree:                                        ; preds = %FinalCleanup, %CoroNormalFinal<br>  %34 = phi i1 [ false, %FinalCleanup ], [ true, %CoroNormalFinal ], !dbg !245<br>  br i1 %8, label %DynFree, label %EndFree, !dbg !245<br><br>DynFree:                                          ; preds = %CheckFree<br>  %35 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 2, !dbg !245<br>  %36 = load void (%Allocator*, %"[]u8"*)*, void (%Allocator*, %"[]u8"*)** %35, align 8, !dbg !245<br>  call fastcc void %36(%Allocator* %1, %"[]u8"* byval %21), !dbg !245<br>  br label %EndFree, !dbg !245<br><br>EndFree:                                          ; preds = %DynFree, %CheckFree<br>  br i1 %34, label %Resume, label %Return, !dbg !245<br><br>Resume:                                           ; preds = %EndFree<br>  %37 = load i8*, i8** %23, align 8, !dbg !245<br>  %38 = load i8*, i8** %23, align 8, !dbg !245<br>  call void @llvm.coro.resume(i8* %38), !dbg !245<br>  br label %Return, !dbg !245<br><br>Return:                                           ; preds = %Resume, %EndFree<br>  ret i8* undef, !dbg !245<br>}<br><br><br></div><div>This triggers:<br><br>"cannot move instruction since its users are not dominated by CoroBegin"<br><br></div>When I use gdb to print I->dump():<br><br>  %8 = getelementptr inbounds %Allocator, %Allocator* %1, i32 0, i32 0, !dbg !71<br><br><br></div>Much to my surprise, this is pointing to an instruction in the `entry` function, not the `amain` coroutine function. Is this a bug?<br><br></div>Thanks for the help,<br></div>Andrew<br><div><div><div><br></div></div></div></div>