diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index c89af688a69ca..b07fa644baa10 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -554,6 +554,7 @@ static void cacheDIVar(FrameDataInfo &FrameData, DIVarCache.insert({V, (*I)->getVariable()}); }; CacheIt(findDVRDeclares(V)); + CacheIt(findDVRDeclareValues(V)); } } @@ -1142,6 +1143,47 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) { for_each(DVRs, SalvageOne); } + TinyPtrVector DVRDeclareValues = + findDVRDeclareValues(Def); + // Try best to find dbg.declare_value. If the spill is a temp, there may + // not be a direct dbg.declare_value. Walk up the load chain to find one + // from an alias. + if (F->getSubprogram()) { + auto *CurDef = Def; + while (DVRDeclareValues.empty() && isa(CurDef)) { + auto *LdInst = cast(CurDef); + // Only consider ptr to ptr same type load. + if (LdInst->getPointerOperandType() != LdInst->getType()) + break; + CurDef = LdInst->getPointerOperand(); + if (!isa(CurDef)) + break; + DVRDeclareValues = findDVRDeclareValues(CurDef); + } + } + + auto SalvageOneCoro = [&](auto *DDI) { + // This dbg.declare_value is preserved for all coro-split function + // fragments. It will be unreachable in the main function, and + // processed by coro::salvageDebugInfo() by the Cloner. However, convert + // it to a dbg.declare to make sure future passes don't have to deal + // with a dbg.declare_value. + auto *VAM = ValueAsMetadata::get(CurrentReload); + Type *Ty = VAM->getValue()->getType(); + // If the metadata type is not a pointer, emit a dbg.value instead. + DbgVariableRecord *NewDVR = new DbgVariableRecord( + ValueAsMetadata::get(CurrentReload), DDI->getVariable(), + DDI->getExpression(), DDI->getDebugLoc(), + Ty->isPointerTy() ? DbgVariableRecord::LocationType::Declare + : DbgVariableRecord::LocationType::Value); + Builder.GetInsertPoint()->getParent()->insertDbgRecordBefore( + NewDVR, Builder.GetInsertPoint()); + // This dbg.declare_value is for the main function entry point. It + // will be deleted in all coro-split functions. + coro::salvageDebugInfo(ArgToAllocaMap, *DDI, false /*UseEntryValue*/); + }; + for_each(DVRDeclareValues, SalvageOneCoro); + // If we have a single edge PHINode, remove it and replace it with a // reload from the coroutine frame. (We already took care of multi edge // PHINodes by normalizing them in the rewritePHIs function). @@ -1925,7 +1967,7 @@ void coro::salvageDebugInfo( Function *F = DVR.getFunction(); // Follow the pointer arithmetic all the way to the incoming // function argument and convert into a DIExpression. - bool SkipOutermostLoad = DVR.isDbgDeclare(); + bool SkipOutermostLoad = DVR.isDbgDeclare() || DVR.isDbgDeclareValue(); Value *OriginalStorage = DVR.getVariableLocationOp(0); auto SalvagedInfo = @@ -1939,10 +1981,11 @@ void coro::salvageDebugInfo( DVR.replaceVariableLocationOp(OriginalStorage, Storage); DVR.setExpression(Expr); - // We only hoist dbg.declare today since it doesn't make sense to hoist - // dbg.value since it does not have the same function wide guarantees that - // dbg.declare does. - if (DVR.getType() == DbgVariableRecord::LocationType::Declare) { + // We only hoist dbg.declare and dbg.declare_value today since it doesn't make + // sense to hoist dbg.value since it does not have the same function wide + // guarantees that dbg.declare does. + if (DVR.getType() == DbgVariableRecord::LocationType::Declare || + DVR.getType() == DbgVariableRecord::LocationType::DeclareValue) { std::optional InsertPt; if (auto *I = dyn_cast(Storage)) { InsertPt = I->getInsertionPointAfterDef(); @@ -1957,6 +2000,19 @@ void coro::salvageDebugInfo( InsertPt = F->getEntryBlock().begin(); if (InsertPt) { DVR.removeFromParent(); + // If there is a dbg.declare_value being reinserted, insert it as a + // dbg.declare instead, so that subsequent passes don't have to deal with + // a dbg.declare_value. + if (DVR.getType() == DbgVariableRecord::LocationType::DeclareValue) { + auto *MD = DVR.getRawLocation(); + if (auto *VAM = dyn_cast(MD)) { + Type *Ty = VAM->getValue()->getType(); + if (Ty->isPointerTy()) + DVR.Type = DbgVariableRecord::LocationType::Declare; + else + DVR.Type = DbgVariableRecord::LocationType::Value; + } + } (*InsertPt)->getParent()->insertDbgRecordBefore(&DVR, *InsertPt); } } diff --git a/llvm/test/Transforms/Coroutines/declare-value.ll b/llvm/test/Transforms/Coroutines/declare-value.ll new file mode 100644 index 0000000000000..94049c28169b9 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/declare-value.ll @@ -0,0 +1,68 @@ +;RUN: opt -mtriple='arm64-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s + +; CHECK: %.debug = alloca double, align 8 +; CHECK-NEXT: #dbg_declare(ptr %{{.*}}, !{{[0-9]+}}, !DIExpression(DW_OP_deref), !{{[0-9]+}}) +; CHECK-NEXT: store double %{{[0-9]+}}, ptr %{{.*}}, align 8 +; CHECK-NEXT: #dbg_declare(ptr %arg, !{{[0-9]+}}, !DIExpression(DW_OP_plus_uconst, 24), !{{[0-9]+}}) + +; ModuleID = '/Users/srastogi/Development/llvm-project-2/llvm/test/Transforms/Coroutines/declare-value.ll' +source_filename = "/Users/srastogi/Development/llvm-project-2/llvm/test/Transforms/Coroutines/declare-value.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32" +target triple = "arm64-unknown" + +@coroutineATu = global <{ i32, i32 }> <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @coroutineA to i64), i64 ptrtoint (ptr @coroutineATu to i64)) to i32), i32 16 }>, align 8 + +; Function Attrs: presplitcoroutine +define swifttailcc void @coroutineA(ptr swiftasync %arg, double %0) #0 !dbg !1 { + %var_with_dbg_value = alloca ptr, align 8 + %var_with_dbg_declare = alloca ptr, align 8 + #dbg_declare(ptr %var_with_dbg_declare, !5, !DIExpression(), !7) + #dbg_declare_value(double %0, !5, !DIExpression(), !7) + %i2 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr nonnull @coroutineATu) + %i3 = call ptr @llvm.coro.begin(token %i2, ptr null) + %i7 = call ptr @llvm.coro.async.resume(), !dbg !7 + %i10 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %i7, ptr nonnull @__swift_async_resume_get_context, ptr nonnull @coroutineA.1, ptr %i7, i64 0, i64 0, ptr %arg), !dbg !7 + call void @dont_optimize(ptr %var_with_dbg_value, ptr %var_with_dbg_declare), !dbg !7 + unreachable, !dbg !7 +} + +define weak_odr hidden ptr @__swift_async_resume_get_context(ptr %arg) !dbg !8 { + ret ptr %arg, !dbg !9 +} + +define hidden swifttailcc void @coroutineA.1(ptr %arg, i64 %arg1, i64 %arg2, ptr %arg3) !dbg !10 { + ret void, !dbg !11 +} + +declare void @dont_optimize(ptr, ptr) + +; Function Attrs: nomerge nounwind +declare ptr @llvm.coro.async.resume() #1 + +; Function Attrs: nounwind +declare ptr @llvm.coro.begin(token, ptr writeonly) #2 + +; Function Attrs: nounwind +declare token @llvm.coro.id.async(i32, i32, i32, ptr) #2 + +; Function Attrs: nomerge nounwind +declare { ptr } @llvm.coro.suspend.async.sl_p0s(i32, ptr, ptr, ...) #1 + +attributes #0 = { presplitcoroutine } +attributes #1 = { nomerge nounwind } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DISubprogram(scope: null, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) +!2 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +!3 = !DIFile(filename: "blah", directory: "") +!4 = !{} +!5 = !DILocalVariable(scope: !1, type: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Klass") +!7 = !DILocation(line: 0, scope: !1) +!8 = distinct !DISubprogram(scope: null, spFlags: DISPFlagDefinition, unit: !2) +!9 = !DILocation(line: 0, scope: !8) +!10 = distinct !DISubprogram(scope: null, spFlags: DISPFlagDefinition, unit: !2) +!11 = !DILocation(line: 0, scope: !10) \ No newline at end of file