Andrew Kelley via llvm-dev
2018-Feb-26 06:14 UTC
[llvm-dev] problem with moveSpillUsesAfterCoroBegin
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>