Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 61 additions & 5 deletions llvm/lib/Transforms/Coroutines/CoroFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ static void cacheDIVar(FrameDataInfo &FrameData,
DIVarCache.insert({V, (*I)->getVariable()});
};
CacheIt(findDVRDeclares(V));
CacheIt(findDVRDeclareValues(V));
}
}

Expand Down Expand Up @@ -1142,6 +1143,47 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
for_each(DVRs, SalvageOne);
}

TinyPtrVector<DbgVariableRecord *> 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<LoadInst>(CurDef)) {
auto *LdInst = cast<LoadInst>(CurDef);
// Only consider ptr to ptr same type load.
if (LdInst->getPointerOperandType() != LdInst->getType())
break;
CurDef = LdInst->getPointerOperand();
if (!isa<AllocaInst, LoadInst>(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).
Expand Down Expand Up @@ -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 =
Expand All @@ -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<BasicBlock::iterator> InsertPt;
if (auto *I = dyn_cast<Instruction>(Storage)) {
InsertPt = I->getInsertionPointAfterDef();
Expand All @@ -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<ValueAsMetadata>(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);
}
}
Expand Down
68 changes: 68 additions & 0 deletions llvm/test/Transforms/Coroutines/declare-value.ll
Original file line number Diff line number Diff line change
@@ -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)