Skip to content

Commit c241ff3

Browse files
committed
Emit compiler-generated debug locations for outlined transparent functions.
In the majority of the use-cases transparent functions are inlined by the mandatory inliner which by design drops all debug info and pretends the inlined instructions were always part of the caller. Since an outlined copy of the function is often still generated, attaching debug locations to it is inconsistent and can create the false impression that it were possible to set a breakpoint in such a function when in reality these functions are only there for very few edge cases. <rdar://problem/40258813>
1 parent 6e5605a commit c241ff3

File tree

6 files changed

+65
-15
lines changed

6 files changed

+65
-15
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3332,7 +3332,8 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
33323332
FunctionPointer witnessFnPtr(witness, sig);
33333333

33343334
// Call the accessor.
3335-
assert((!IGF.IGM.DebugInfo || IGF.Builder.getCurrentDebugLocation()) &&
3335+
assert((!IGF.IGM.DebugInfo || IGF.Builder.getCurrentDebugLocation() ||
3336+
!IGF.CurFn->getSubprogram()) &&
33363337
"creating a function call without a debug location");
33373338
auto call = IGF.Builder.CreateCall(witnessFnPtr,
33383339
{ request.get(IGF),

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
286286

287287
auto L = decodeDebugLoc(CS->Loc);
288288
auto Scope = getOrCreateScope(CS->Parent.dyn_cast<const SILDebugScope *>());
289+
// Pretend transparent functions don't exist.
290+
if (!Scope)
291+
return createInlinedAt(CS);
289292
auto InlinedAt =
290293
llvm::DebugLoc::get(L.Line, L.Column, Scope, createInlinedAt(CS));
291294
InlinedAtCache.insert(
@@ -1563,7 +1566,7 @@ void IRGenDebugInfoImpl::setCurrentLoc(IRBuilder &Builder,
15631566

15641567
SILLocation::DebugLoc L;
15651568
SILFunction *Fn = DS->getInlinedFunction();
1566-
if (Fn && Fn->isThunk()) {
1569+
if (Fn && (Fn->isThunk() || Fn->isTransparent())) {
15671570
L = SILLocation::getCompilerGeneratedDebugLoc();
15681571
} else if (DS == LastScope && Loc.isAutoGenerated()) {
15691572
// Reuse the last source location if we are still in the same
@@ -1735,6 +1738,7 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
17351738
// Some IRGen-generated helper functions don't have a corresponding
17361739
// SIL function, hence the dyn_cast.
17371740
auto *SILFn = DS ? DS->Parent.dyn_cast<SILFunction *>() : nullptr;
1741+
17381742
StringRef LinkageName;
17391743
if (Fn)
17401744
LinkageName = Fn->getName();
@@ -1754,17 +1758,18 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
17541758
/// The source line used for the function prologue.
17551759
unsigned ScopeLine = 0;
17561760
SILLocation::DebugLoc L;
1757-
if (DS && (!SILFn || (!SILFn->isBare() && !SILFn->isThunk()))) {
1761+
if (!DS || (SILFn && (SILFn->isBare() || SILFn->isThunk() ||
1762+
SILFn->isTransparent()))) {
17581763
// Bare functions and thunks should not have any line numbers. This
17591764
// is especially important for shared functions like reabstraction
17601765
// thunk helpers, where DS->Loc is an arbitrary location of whichever use
17611766
// was emitted first.
1767+
L = SILLocation::getCompilerGeneratedDebugLoc();
1768+
} else {
17621769
L = decodeDebugLoc(DS->Loc);
17631770
ScopeLine = L.Line;
17641771
if (!DS->Loc.isDebugInfoLoc())
17651772
L = decodeSourceLoc(DS->Loc.getSourceLoc());
1766-
} else {
1767-
L = SILLocation::getCompilerGeneratedDebugLoc();
17681773
}
17691774

17701775
auto Line = L.Line;
@@ -1882,7 +1887,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
18821887
if (!DbgTy.size)
18831888
DbgTy.size = getStorageSize(IGM.DataLayout, Storage);
18841889

1885-
auto *Scope = dyn_cast<llvm::DILocalScope>(getOrCreateScope(DS));
1890+
auto *Scope = dyn_cast_or_null<llvm::DILocalScope>(getOrCreateScope(DS));
18861891
assert(Scope && "variable has no local scope");
18871892
auto Loc = getDebugLoc(*this, VarDecl);
18881893

@@ -2028,13 +2033,17 @@ void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
20282033
if (Opts.DebugInfoKind <= IRGenDebugInfoKind::LineTables)
20292034
return;
20302035

2036+
// Don't emit debug info in transparent functions.
2037+
auto *DS = IGF.getDebugScope();
2038+
if (!DS || DS->getInlinedFunction()->isTransparent())
2039+
return;
2040+
20312041
auto TName = BumpAllocatedString(("$swift.type." + Name).str());
20322042
auto DbgTy = DebugTypeInfo::getMetadata(
20332043
getMetadataType()->getDeclaredInterfaceType().getPointer(),
20342044
Metadata->getType(), Size(CI.getTargetInfo().getPointerWidth(0)),
20352045
Alignment(CI.getTargetInfo().getPointerAlign(0)));
2036-
emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(),
2037-
nullptr, TName, 0,
2046+
emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, DS, nullptr, TName, 0,
20382047
// swift.type is already a pointer type,
20392048
// having a shadow copy doesn't add another
20402049
// layer of indirection.

lib/IRGen/IRGenSIL.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,8 +1771,8 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
17711771
for (auto &I : *BB) {
17721772
if (IGM.DebugInfo) {
17731773
// Set the debug info location for I, if applicable.
1774-
SILLocation ILoc = I.getLoc();
17751774
auto DS = I.getDebugScope();
1775+
SILLocation ILoc = I.getLoc();
17761776
// Handle cleanup locations.
17771777
if (ILoc.is<CleanupLocation>()) {
17781778
// Cleanup locations point to the decl of the value that is
@@ -1830,9 +1830,8 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
18301830
emitDebugVariableRangeExtension(BB);
18311831
}
18321832
visit(&I);
1833-
18341833
}
1835-
1834+
18361835
assert(Builder.hasPostTerminatorIP() && "SIL bb did not terminate block?!");
18371836
}
18381837

@@ -3647,6 +3646,9 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
36473646
if (!IGM.DebugInfo)
36483647
return;
36493648

3649+
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
3650+
return;
3651+
36503652
auto VarInfo = i->getVarInfo();
36513653
assert(VarInfo && "debug_value without debug info");
36523654
auto SILVal = i->getOperand();
@@ -3689,6 +3691,10 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
36893691
void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
36903692
if (!IGM.DebugInfo)
36913693
return;
3694+
3695+
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
3696+
return;
3697+
36923698
VarDecl *Decl = i->getDecl();
36933699
if (!Decl)
36943700
return;
@@ -3968,6 +3974,9 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
39683974
if (!DS)
39693975
return;
39703976

3977+
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
3978+
return;
3979+
39713980
bool IsAnonymous = false;
39723981
StringRef Name = getVarName(i, IsAnonymous);
39733982

@@ -4171,6 +4180,9 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) {
41714180
DbgName);
41724181
setLoweredBox(i, boxWithAddr);
41734182

4183+
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
4184+
return;
4185+
41744186
if (IGM.DebugInfo && Decl) {
41754187
// FIXME: This is a workaround to not produce local variables for
41764188
// capture list arguments like "[weak self]". The better solution

test/DebugInfo/autoclosure.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func &&&&&(lhs: Bool, rhs: @autoclosure () -> Bool) -> Bool {
2121
func call_me(_ input: Int64) -> Void {
2222
// rdar://problem/14627460
2323
// An autoclosure should have a line number in the debug info and a scope line of 0.
24-
// CHECK-DAG: !DISubprogram({{.*}}linkageName: "$S11autoclosure7call_meyys5Int64VFSbyXKfu_",{{.*}} line: [[@LINE+3]],{{.*}} isLocal: true, isDefinition: true
24+
// CHECK-DAG: !DISubprogram({{.*}}linkageName: "$S11autoclosure7call_meyys5Int64VFSbyXKfu_",{{.*}} isLocal: true, isDefinition: true
2525
// But not in the line table.
2626
// CHECK-DAG: ![[DBG]] = !DILocation(line: [[@LINE+1]],
2727
if input != 0 &&&&& ( get_truth (input * 2 + 1) > 0 ) {

test/DebugInfo/generic_enum_closure.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ struct CErrorOr<T>
1515
// CHECK-SAME: !DIExpression(DW_OP_deref))
1616
// CHECK-DAG: store i8* %[[DYN:.*]], i8** %[[SHADOW]]
1717
// CHECK-DAG: %[[DYN]] = alloca i8, i{{32|64}} %
18-
// CHECK: ![[T1:.*]] = !DICompositeType({{.*}}, identifier: "$S20generic_enum_closure8CErrorOrVyACQq_GD")
19-
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope:
20-
// CHECK-SAME: type: ![[T1]])
18+
// CHECK-DAG: ![[T1:.*]] = !DICompositeType({{.*}}, identifier: "$S20generic_enum_closure8CErrorOrVyACQq_GD")
19+
// CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", scope:{{.*}}, type: ![[T1]])
2120
value = .none
2221
}
2322
}

test/DebugInfo/transparent.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend %s -O -I %t -emit-ir -g -o - | %FileCheck %s
2+
3+
func use<T>(_ t: T) {}
4+
5+
@inline(never)
6+
public func noinline(_ x: Int64) -> Int64 { return x }
7+
8+
@_transparent
9+
public func transparent(_ y: Int64) -> Int64 {
10+
var local = y
11+
return noinline(local)
12+
}
13+
14+
let z = transparent(0)
15+
use(z)
16+
17+
// Check that a transparent function has no debug information.
18+
// CHECK: define {{.*}}$S11transparentAA
19+
// CHECK-SAME: !dbg ![[SP:[0-9]+]]
20+
// CHECK-NEXT: entry:
21+
// CHECK-NEXT: !dbg ![[ZERO:[0-9]+]]
22+
// CHECK-NEXT: !dbg ![[ZERO]]
23+
// CHECK-NEXT: }
24+
25+
// CHECK: ![[SP]] = {{.*}}name: "transparent"
26+
// CHECK-SAME: file: ![[FILE:[0-9]+]]
27+
// CHECK-NOT: line:
28+
// CHECK: ![[FILE]] = {{.*}}"<compiler-generated>"
29+
// CHECK: ![[ZERO]] = !DILocation(line: 0,

0 commit comments

Comments
 (0)