diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -25,8 +25,11 @@ const std::initializer_list); void replaceCoroFree(CoroIdInst *CoroId, bool Elide); -/// Recover a dbg.declare prepared by the frontend and emit an alloca -/// holding a pointer to the coroutine frame. +/// Attempts to rewrite the location operand of debug intrinsics in terms of +/// the coroutine frame pointer, folding pointer offsets into the DIExpression +/// of the intrinsic. +/// If the frame pointer is an Argument, store it into an alloca if +/// OptimizeFrame is false. void salvageDebugInfo( SmallDenseMap &DbgPtrAllocaCache, DbgVariableIntrinsic *DVI, bool OptimizeFrame); diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -680,17 +680,24 @@ } } +/// Returns all DbgVariableIntrinsic in F. +static SmallVector +collectDbgVariableIntrinsics(Function &F) { + SmallVector Intrinsics; + for (auto &I : instructions(F)) + if (auto *DVI = dyn_cast(&I)) + Intrinsics.push_back(DVI); + return Intrinsics; +} + void CoroCloner::replaceSwiftErrorOps() { ::replaceSwiftErrorOps(*NewF, Shape, &VMap); } void CoroCloner::salvageDebugInfo() { - SmallVector Worklist; + SmallVector Worklist = + collectDbgVariableIntrinsics(*NewF); SmallDenseMap DbgPtrAllocaCache; - for (auto &BB : *NewF) - for (auto &I : BB) - if (auto *DVI = dyn_cast(&I)) - Worklist.push_back(DVI); for (DbgVariableIntrinsic *DVI : Worklist) coro::salvageDebugInfo(DbgPtrAllocaCache, DVI, Shape.OptimizeFrame); @@ -1971,20 +1978,11 @@ // This invalidates SwiftErrorOps in the Shape. replaceSwiftErrorOps(F, Shape, nullptr); - // Finally, salvage the llvm.dbg.declare in our original function that point - // into the coroutine frame. We only do this for the current function since - // the Cloner salvaged debug info for us in the new coroutine funclets. - SmallVector Worklist; + // Salvage debug intrinsics that point into the coroutine frame in the + // original function. The Cloner has already salvaged debug info in the new + // coroutine funclets. SmallDenseMap DbgPtrAllocaCache; - for (auto &BB : F) { - for (auto &I : BB) { - if (auto *DDI = dyn_cast(&I)) { - Worklist.push_back(DDI); - continue; - } - } - } - for (auto *DDI : Worklist) + for (auto *DDI : collectDbgVariableIntrinsics(F)) coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, Shape.OptimizeFrame); return Shape; diff --git a/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll b/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll --- a/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll @@ -2,13 +2,34 @@ ; RUN: opt < %s -passes='module(coro-early),cgscc(coro-split,coro-split)' -S | FileCheck %s ; ; This file is based on coro-debug-frame-variable.ll. -; CHECK: define internal fastcc void @f.resume(ptr noundef nonnull align 16 dereferenceable(80) %begin) !dbg ![[RESUME_FN_DBG_NUM:[0-9]+]] +; CHECK-LABEL: define void @f( +; CHECK: %[[frame:.*]] = call {{.*}} @llvm.coro.begin +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame]] +; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, [[OffsetX:[0-9]*]])) +; ^ No deref at the end, as this variable ("x") is an array; +; its value is its address. The entire array is in the frame. +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame]] +; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, [[OffsetSpill:[0-9]*]], DW_OP_deref)) +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame]] +; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, [[OffsetI:[0-9]*]], DW_OP_deref)) +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame]] +; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, [[OffsetJ:[0-9]*]], DW_OP_deref)) + +; CHECK-LABEL: void @f.resume( +; CHECK-SAME: ptr {{.*}} %[[frame:.*]]) +; CHECK-SAME: !dbg ![[RESUME_FN_DBG_NUM:[0-9]+]] +; CHECK: %[[frame_alloca:.*]] = alloca ptr +; CHECK-NEXT: store ptr %[[frame]], ptr %[[frame_alloca]] ; CHECK: init.ready: -; CHECK: call void @llvm.dbg.value(metadata ptr %begin.debug, metadata ![[XVAR_RESUME:[0-9]+]], +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame_alloca]], metadata ![[XVAR_RESUME:[0-9]+]], +; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[OffsetX]]) ; CHECK: await.ready: -; CHECK: call void @llvm.dbg.value(metadata ptr %begin.debug, metadata ![[SPILL_RESUME:[0-9]+]] -; CHECK: call void @llvm.dbg.value(metadata ptr %begin.debug, metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression( -; CHECK: call void @llvm.dbg.value(metadata ptr %begin.debug, metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression( +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame_alloca]], metadata ![[SPILL_RESUME:[0-9]+]] +; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[OffsetSpill]], DW_OP_deref) +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame_alloca]], metadata ![[IVAR_RESUME:[0-9]+]], +; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[OffsetI]], DW_OP_deref) +; CHECK: call void @llvm.dbg.value(metadata ptr %[[frame_alloca]], metadata ![[JVAR_RESUME:[0-9]+]], +; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[OffsetJ]], DW_OP_deref) ; ; CHECK: ![[RESUME_FN_DBG_NUM]] = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov" ; CHECK: ![[IVAR_RESUME]] = !DILocalVariable(name: "i" @@ -16,7 +37,6 @@ ; CHECK: ![[JVAR_RESUME]] = !DILocalVariable(name: "j" ; CHECK: ![[SPILL_RESUME]] = !DILocalVariable(name: "produced" -source_filename = "../llvm/test/Transforms/Coroutines/coro-debug-dbg.values-O2.ll" declare void @consume(i32) define void @f(i32 %i, i32 %j) presplitcoroutine !dbg !8 {