Skip to content

Commit 9671dbf

Browse files
Merge pull request #35028 from adrian-prantl/71866936
Add debug info support for function arguments in async functions.
2 parents 296ab5f + 0e6a0b8 commit 9671dbf

File tree

5 files changed

+110
-26
lines changed

5 files changed

+110
-26
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
197197
void emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage,
198198
llvm::DILocalVariable *Var, llvm::DIExpression *Expr,
199199
unsigned Line, unsigned Col, llvm::DILocalScope *Scope,
200-
const SILDebugScope *DS);
200+
const SILDebugScope *DS, bool InCoroContext = false);
201201
void emitGlobalVariableDeclaration(llvm::GlobalVariable *Storage,
202202
StringRef Name, StringRef LinkageName,
203203
DebugTypeInfo DebugType,
@@ -2367,7 +2367,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
23672367

23682368
for (llvm::Value *Piece : Storage) {
23692369
SmallVector<uint64_t, 3> Operands;
2370-
if (Indirection)
2370+
if (Indirection == IndirectValue || Indirection == CoroIndirectValue)
23712371
Operands.push_back(llvm::dwarf::DW_OP_deref);
23722372

23732373
if (IsPiece) {
@@ -2389,7 +2389,9 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
23892389
Operands.push_back(SizeInBits);
23902390
}
23912391
emitDbgIntrinsic(Builder, Piece, Var, DBuilder.createExpression(Operands),
2392-
Line, Loc.Column, Scope, DS);
2392+
Line, Loc.Column, Scope, DS,
2393+
Indirection == CoroDirectValue ||
2394+
Indirection == CoroIndirectValue);
23932395
}
23942396

23952397
// Emit locationless intrinsic for variables that were optimized away.
@@ -2401,7 +2403,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
24012403
void IRGenDebugInfoImpl::emitDbgIntrinsic(
24022404
IRBuilder &Builder, llvm::Value *Storage, llvm::DILocalVariable *Var,
24032405
llvm::DIExpression *Expr, unsigned Line, unsigned Col,
2404-
llvm::DILocalScope *Scope, const SILDebugScope *DS) {
2406+
llvm::DILocalScope *Scope, const SILDebugScope *DS, bool InCoroContext) {
24052407
// Set the location/scope of the intrinsic.
24062408
auto *InlinedAt = createInlinedAt(DS);
24072409
auto DL = llvm::DebugLoc::get(Line, Col, Scope, InlinedAt);
@@ -2420,13 +2422,23 @@ void IRGenDebugInfoImpl::emitDbgIntrinsic(
24202422
DBuilder.insertDeclare(Alloca, Var, Expr, DL, &*InsertBefore);
24212423
else
24222424
DBuilder.insertDeclare(Alloca, Var, Expr, DL, ParentBB);
2423-
} else if (isa<llvm::IntrinsicInst>(Storage) &&
2424-
cast<llvm::IntrinsicInst>(Storage)->getIntrinsicID() ==
2425-
llvm::Intrinsic::coro_alloca_get) {
2425+
} else if ((isa<llvm::IntrinsicInst>(Storage) &&
2426+
cast<llvm::IntrinsicInst>(Storage)->getIntrinsicID() ==
2427+
llvm::Intrinsic::coro_alloca_get)) {
24262428
// FIXME: The live range of a coroutine alloca within the function may be
24272429
// limited, so using a dbg.addr instead of a dbg.declare would be more
24282430
// appropriate.
24292431
DBuilder.insertDeclare(Storage, Var, Expr, DL, BB);
2432+
} else if (InCoroContext && (Var->getArg() || Var->isArtificial())) {
2433+
// Function arguments in async functions are emitted without a shadow copy
2434+
// (that would interfer with coroutine splitting) but with a dbg.declare to
2435+
// give CoroSplit.cpp license to emit a shadow copy for them pointing inside
2436+
// the Swift Context argument that is valid throughout the function.
2437+
auto &EntryBlock = BB->getParent()->getEntryBlock();
2438+
if (auto *InsertBefore = &*EntryBlock.getFirstInsertionPt())
2439+
DBuilder.insertDeclare(Storage, Var, Expr, DL, InsertBefore);
2440+
else
2441+
DBuilder.insertDeclare(Storage, Var, Expr, DL, &EntryBlock);
24302442
} else {
24312443
// Insert a dbg.value at the current insertion point.
24322444
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
@@ -2506,7 +2518,8 @@ void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
25062518
// swift.type is already a pointer type,
25072519
// having a shadow copy doesn't add another
25082520
// layer of indirection.
2509-
DirectValue, ArtificialValue);
2521+
IGF.isAsync() ? CoroDirectValue : DirectValue,
2522+
ArtificialValue);
25102523
}
25112524

25122525
SILLocation::DebugLoc IRGenDebugInfoImpl::decodeSourceLoc(SourceLoc SL) {
@@ -2609,9 +2622,10 @@ void IRGenDebugInfo::emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage,
26092622
llvm::DILocalVariable *Var,
26102623
llvm::DIExpression *Expr, unsigned Line,
26112624
unsigned Col, llvm::DILocalScope *Scope,
2612-
const SILDebugScope *DS) {
2625+
const SILDebugScope *DS,
2626+
bool InCoroContext) {
26132627
static_cast<IRGenDebugInfoImpl *>(this)->emitDbgIntrinsic(
2614-
Builder, Storage, Var, Expr, Line, Col, Scope, DS);
2628+
Builder, Storage, Var, Expr, Line, Col, Scope, DS, InCoroContext);
26152629
}
26162630

26172631
void IRGenDebugInfo::emitGlobalVariableDeclaration(

lib/IRGen/IRGenDebugInfo.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ class IRBuilder;
3838
class IRGenFunction;
3939
class IRGenModule;
4040

41-
enum IndirectionKind : bool { DirectValue = false, IndirectValue = true };
41+
enum IndirectionKind {
42+
DirectValue,
43+
IndirectValue,
44+
CoroDirectValue,
45+
CoroIndirectValue
46+
};
4247
enum ArtificialKind : bool { RealValue = false, ArtificialValue = true };
4348

4449
/// Helper object that keeps track of the current CompileUnit, File,
@@ -61,10 +66,11 @@ class IRGenDebugInfo {
6166
void setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS,
6267
SILLocation Loc);
6368

64-
/// Replace the current debug location in \p Builder with the same location, but contained in an
65-
/// inlined function which is named like \p failureMsg.
69+
/// Replace the current debug location in \p Builder with the same location,
70+
/// but contained in an inlined function which is named like \p failureMsg.
6671
///
67-
/// This lets the debugger display the \p failureMsg as an inlined function frame.
72+
/// This lets the debugger display the \p failureMsg as an inlined function
73+
/// frame.
6874
void addFailureMessageToCurrentLoc(IRBuilder &Builder, StringRef failureMsg);
6975

7076
void clearLoc(IRBuilder &Builder);
@@ -143,7 +149,7 @@ class IRGenDebugInfo {
143149
void emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage,
144150
llvm::DILocalVariable *Var, llvm::DIExpression *Expr,
145151
unsigned Line, unsigned Col, llvm::DILocalScope *Scope,
146-
const SILDebugScope *DS);
152+
const SILDebugScope *DS, bool InCoroContext = false);
147153

148154
enum { NotHeapAllocated = false };
149155

lib/IRGen/IRGenSIL.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -726,9 +726,9 @@ class IRGenSILFunction :
726726

727727
/// Unconditionally emit a stack shadow copy of an \c llvm::Value.
728728
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
729-
SILDebugVariable VarInfo, llvm::Optional<Alignment> _Align) {
729+
SILDebugVariable VarInfo,
730+
llvm::Optional<Alignment> _Align) {
730731
auto Align = _Align.getValueOr(IGM.getPointerAlignment());
731-
732732
unsigned ArgNo = VarInfo.ArgNo;
733733
auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, VarInfo.Name}}];
734734
if (!Alloca.isValid())
@@ -750,10 +750,13 @@ class IRGenSILFunction :
750750
SILDebugVariable VarInfo,
751751
bool IsAnonymous,
752752
llvm::Optional<Alignment> Align = None) {
753-
// Never emit shadow copies when optimizing, or if already on the stack.
754-
// No debug info is emitted for refcounts either.
753+
// Never emit shadow copies when optimizing, or if already on the stack. No
754+
// debug info is emitted for refcounts either. Shadow copies are also
755+
// turned off for async functions, because they make it impossible to track
756+
// debug info during coroutine splitting. Instead we are relying on LLVM's
757+
// CoroSplit.cpp to emit shadow copies.
755758
if (IGM.IRGen.Opts.DisableDebuggerShadowCopies ||
756-
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
759+
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous || CurSILFn->isAsync() ||
757760
isa<llvm::AllocaInst>(Storage) || isa<llvm::UndefValue>(Storage) ||
758761
!needsShadowCopy(Storage))
759762
return Storage;
@@ -780,7 +783,7 @@ class IRGenSILFunction :
780783

781784
// Only do this at -O0.
782785
if (IGM.IRGen.Opts.DisableDebuggerShadowCopies ||
783-
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous) {
786+
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous || CurSILFn->isAsync()) {
784787
auto vals = e.claimAll();
785788
copy.append(vals.begin(), vals.end());
786789
return;
@@ -4334,8 +4337,28 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
43344337
assert(VarInfo && "debug_value_addr without debug info");
43354338
bool IsAnonymous = false;
43364339
bool IsLoadablyByAddress = isa<AllocStackInst>(SILVal);
4340+
IndirectionKind Indirection =
4341+
(IsLoadablyByAddress) ? DirectValue : IndirectValue;
43374342
VarInfo->Name = getVarName(i, IsAnonymous);
4338-
auto Addr = getLoweredAddress(SILVal).getAddress();
4343+
auto *Addr = getLoweredAddress(SILVal).getAddress();
4344+
if (CurSILFn->isAsync() && VarInfo->ArgNo) {
4345+
#ifndef NDEBUG
4346+
llvm::Value *Storage = Addr;
4347+
while (Storage) {
4348+
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Storage))
4349+
Storage = LdInst->getOperand(0);
4350+
else if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Storage))
4351+
Storage = GEPInst->getOperand(0);
4352+
else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
4353+
Storage = BCInst->getOperand(0);
4354+
else
4355+
break;
4356+
}
4357+
assert(llvm::isa<llvm::Argument>(Storage) &&
4358+
"arg expected to be load from inside %swift.context");
4359+
#endif
4360+
Indirection = CoroIndirectValue;
4361+
}
43394362
SILType SILTy = SILVal->getType();
43404363
auto RealType = SILTy.getASTType();
43414364

@@ -4349,8 +4372,7 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
43494372
// intrinsic.
43504373
emitDebugVariableDeclaration(
43514374
emitShadowCopyIfNeeded(Addr, i->getDebugScope(), *VarInfo, IsAnonymous),
4352-
DbgTy, SILType(), i->getDebugScope(), Decl, *VarInfo,
4353-
(IsLoadablyByAddress) ? DirectValue : IndirectValue);
4375+
DbgTy, SILType(), i->getDebugScope(), Decl, *VarInfo, Indirection);
43544376
}
43554377

43564378
void IRGenSILFunction::visitFixLifetimeInst(swift::FixLifetimeInst *i) {

lib/IRGen/LocalTypeData.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,9 @@ static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
344344

345345
llvm::Value *data = value.getMetadata();
346346

347-
// At -O0, create an alloca to keep the type alive.
348-
if (!IGF.IGM.IRGen.Opts.shouldOptimize()) {
347+
// At -O0, create an alloca to keep the type alive. Not for async functions
348+
// though; see the comment in IRGenFunctionSIL::emitShadowCopyIfNeeded().
349+
if (!IGF.IGM.IRGen.Opts.shouldOptimize() && !IGF.isAsync()) {
349350
auto alloca =
350351
IGF.createAlloca(data->getType(), IGF.IGM.getPointerAlignment(), name);
351352
IGF.Builder.CreateStore(data, alloca);

test/DebugInfo/async-args.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -g -o - \
2+
// RUN: -module-name M -enable-experimental-concurrency | %FileCheck %s
3+
4+
func use<T>(_ t: T) {}
5+
func forceSplit() async {
6+
}
7+
func withGenericArg<T>(_ msg: T) async {
8+
// This odd debug info is part of a contract with CoroSplit/CoroFrame to fix
9+
// this up after coroutine splitting.
10+
// CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYlF"(%swift.task* %0, %swift.executor* %1, %swift.context* %2)
11+
// CHECK: call void @llvm.dbg.declare(metadata %swift.context** %[[ALLOCA:[^,]*]],
12+
// CHECK-SAME: metadata ![[MSG:[0-9]+]], metadata !DIExpression(
13+
// CHECK-SAME: DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref))
14+
// CHECK: call void @llvm.dbg.declare(metadata %swift.context** %[[ALLOCA]],
15+
// CHECK-SAME: metadata ![[TAU:[0-9]+]], metadata !DIExpression(
16+
// CHECK-SAME: DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}))
17+
// CHECK: store %swift.context* %2, %swift.context** %[[ALLOCA]], align
18+
19+
await forceSplit()
20+
// CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYlF.resume.0"(i8* %0, i8* %1, i8* %2)
21+
// CHECK: store i8* %2, i8** %[[ALLOCA:.*]], align
22+
// CHECK: call void @llvm.dbg.declare(metadata i8** %[[ALLOCA]],
23+
// CHECK-SAME: metadata ![[TAU_R:[0-9]+]], metadata !DIExpression(
24+
// CHECK-SAME: DW_OP_deref, DW_OP_plus_uconst, [[OFFSET:[0-9]+]],
25+
// CHECK-SAME: DW_OP_plus_uconst, {{[0-9]+}}))
26+
// CHECK: call void @llvm.dbg.declare(metadata i8** %[[ALLOCA]],
27+
// CHECK-SAME: metadata ![[MSG_R:[0-9]+]], metadata !DIExpression(
28+
// CHECK-SAME: DW_OP_deref, DW_OP_plus_uconst, [[OFFSET]],
29+
// CHECK-SAME: DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref))
30+
31+
use(msg)
32+
}
33+
// CHECK-LABEL: {{^define }}
34+
runAsyncAndBlock {
35+
await withGenericArg("hello (asynchronously)")
36+
}
37+
// CHECK: ![[MSG]] = !DILocalVariable(name: "msg", arg: 1,
38+
// CHECK: ![[TAU]] = !DILocalVariable(name: "$\CF\84_0_0",
39+
// CHECK: ![[TAU_R]] = !DILocalVariable(name: "$\CF\84_0_0",
40+
// CHECK: ![[MSG_R]] = !DILocalVariable(name: "msg", arg: 1,
41+

0 commit comments

Comments
 (0)