Debug Info: Create artificial functions in a virtual file <compiler-generated>.

For the majority of artificial helper functions the filename is
actively misleading since it usually represents the file of the caller
that triggered the helper to be generated. Instead, this patch creates
a virtual filname `<compiler-generated>` to make it very obvious that
the function has not correspondence to any source code.

<rdar://problem/33809560>
This commit is contained in:
Adrian Prantl
2018-01-12 10:29:58 -08:00
parent c74ae5f375
commit b4781f63ef
5 changed files with 42 additions and 29 deletions

View File

@@ -433,6 +433,12 @@ public:
: decode(getDebugSourceLoc(), SM); : decode(getDebugSourceLoc(), SM);
} }
/// Compiler-generated locations may be applied to instructions without any
/// clear correspondence to an AST node in an otherwise normal function.
static DebugLoc getCompilerGeneratedDebugLoc() {
return {0, 0, "<compiler-generated>"};
}
/// Pretty-print the value. /// Pretty-print the value.
void dump(const SourceManager &SM) const; void dump(const SourceManager &SM) const;
void print(raw_ostream &OS, const SourceManager &SM) const; void print(raw_ostream &OS, const SourceManager &SM) const;
@@ -487,8 +493,11 @@ public:
/// specified type is incorrect, asserts. /// specified type is incorrect, asserts.
template <typename T> T *castTo() const { return castNodeTo<T>(Loc.ASTNode); } template <typename T> T *castTo() const { return castNodeTo<T>(Loc.ASTNode); }
/// Compiler-generated locations may be applied to instructions without any
/// clear correspondence to an AST node in an otherwise normal function.
/// The auto-generated bit also turns off certain diagnostics passes such.
static RegularLocation getAutoGeneratedLocation() { static RegularLocation getAutoGeneratedLocation() {
RegularLocation AL; RegularLocation AL(getCompilerGeneratedDebugLoc());
AL.markAutoGenerated(); AL.markAutoGenerated();
return AL; return AL;
} }
@@ -502,12 +511,6 @@ private:
} }
}; };
/// Compiler-generated locations may be applied to instructions without any
/// clear correspondence to an AST node.
static inline RegularLocation getCompilerGeneratedLocation() {
return {SourceLoc()};
}
/// Used to represent a return instruction in user code. /// Used to represent a return instruction in user code.
/// ///
/// Allowed on an BranchInst, ReturnInst. /// Allowed on an BranchInst, ReturnInst.
@@ -712,7 +715,8 @@ class SILDebugLocation {
public: public:
SILDebugLocation() SILDebugLocation()
: Scope(nullptr), Location(getCompilerGeneratedLocation()) {} : Scope(nullptr),
Location(RegularLocation::getAutoGeneratedLocation()) {}
SILDebugLocation(SILLocation Loc, const SILDebugScope *DS) SILDebugLocation(SILLocation Loc, const SILDebugScope *DS)
: Scope(DS), Location(Loc) {} : Scope(DS), Location(Loc) {}
SILLocation getLocation() const { return Location; } SILLocation getLocation() const { return Location; }

View File

@@ -1561,20 +1561,23 @@ void IRGenDebugInfoImpl::setCurrentLoc(IRBuilder &Builder,
if (!Scope) if (!Scope)
return; return;
SILFunction *Fn = DS->getInlinedFunction();
SILLocation::DebugLoc L; SILLocation::DebugLoc L;
SILFunction *Fn = DS->getInlinedFunction();
if ((Loc && Loc->isAutoGenerated()) || (Fn && Fn->isThunk())) { if (Fn && Fn->isThunk()) {
L = SILLocation::getCompilerGeneratedDebugLoc();
} else if (DS == LastScope && Loc && Loc->isAutoGenerated()) {
// Reuse the last source location if we are still in the same // Reuse the last source location if we are still in the same
// scope to get a more contiguous line table. // scope to get a more contiguous line table.
// Otherwise use a line 0 artificial location.
if (DS == LastScope)
L = LastDebugLoc; L = LastDebugLoc;
else
L.Filename = LastDebugLoc.Filename;
} else { } else {
// Decode the location. // Decode the location.
L = getDebugLocation(Loc); L = getDebugLocation(Loc);
// Otherwise use a line 0 artificial location, but the file from the
// location.
if (Loc && Loc->isAutoGenerated()) {
L.Line = 0;
L.Column = 0;
}
} }
auto *File = getOrCreateFile(L.Filename); auto *File = getOrCreateFile(L.Filename);
@@ -1748,17 +1751,20 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
Name = getName(DS->Loc); Name = getName(DS->Loc);
} }
/// The source line used for the function prologue.
unsigned ScopeLine = 0;
SILLocation::DebugLoc L; SILLocation::DebugLoc L;
unsigned ScopeLine = 0; /// The source line used for the function prologue. if (DS && (!SILFn || (!SILFn->isBare() && !SILFn->isThunk()))) {
// Bare functions and thunks should not have any line numbers. This // Bare functions and thunks should not have any line numbers. This
// is especially important for shared functions like reabstraction // is especially important for shared functions like reabstraction
// thunk helpers, where DS->Loc is an arbitrary location of whichever use // thunk helpers, where DS->Loc is an arbitrary location of whichever use
// was emitted first. // was emitted first.
if (DS && (!SILFn || (!SILFn->isBare() && !SILFn->isThunk()))) {
L = decodeDebugLoc(DS->Loc); L = decodeDebugLoc(DS->Loc);
ScopeLine = L.Line; ScopeLine = L.Line;
if (!DS->Loc.isDebugInfoLoc()) if (!DS->Loc.isDebugInfoLoc())
L = decodeSourceLoc(DS->Loc.getSourceLoc()); L = decodeSourceLoc(DS->Loc.getSourceLoc());
} else {
L = SILLocation::getCompilerGeneratedDebugLoc();
} }
auto Line = L.Line; auto Line = L.Line;
@@ -1769,7 +1775,6 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
// We know that main always comes from MainFile. // We know that main always comes from MainFile.
if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) {
if (L.Filename.empty())
File = MainFile; File = MainFile;
Line = 1; Line = 1;
Name = LinkageName; Name = LinkageName;
@@ -1787,16 +1792,15 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
bool IsLocalToUnit = Fn ? Fn->hasInternalLinkage() : true; bool IsLocalToUnit = Fn ? Fn->hasInternalLinkage() : true;
bool IsDefinition = true; bool IsDefinition = true;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
// Mark everything that is not visible from the source code (i.e., // Mark everything that is not visible from the source code (i.e.,
// does not have a Swift name) as artificial, so the debugger can // does not have a Swift name) as artificial, so the debugger can
// ignore it. Explicit closures are exempt from this rule. We also // ignore it. Explicit closures are exempt from this rule. We also
// make an exception for toplevel code, which, although it does not // make an exception for toplevel code, which, although it does not
// have a Swift name, does appear prominently in the source code. // have a Swift name, does appear prominently in the source code.
if ((Name.empty() && LinkageName != SWIFT_ENTRY_POINT_FUNCTION &&
!isExplicitClosure(SILFn)) ||
// ObjC thunks should also not show up in the linetable, because we // ObjC thunks should also not show up in the linetable, because we
// never want to set a breakpoint there. // never want to set a breakpoint there.
if ((Name.empty() && LinkageName != SWIFT_ENTRY_POINT_FUNCTION &&
!isExplicitClosure(SILFn)) ||
(Rep == SILFunctionTypeRepresentation::ObjCMethod) || (Rep == SILFunctionTypeRepresentation::ObjCMethod) ||
isAllocatingConstructor(Rep, DeclCtx)) { isAllocatingConstructor(Rep, DeclCtx)) {
Flags |= llvm::DINode::FlagArtificial; Flags |= llvm::DINode::FlagArtificial;
@@ -1849,7 +1853,9 @@ void IRGenDebugInfoImpl::emitArtificialFunction(IRBuilder &Builder,
RegularLocation ALoc = RegularLocation::getAutoGeneratedLocation(); RegularLocation ALoc = RegularLocation::getAutoGeneratedLocation();
const SILDebugScope *Scope = new (IGM.getSILModule()) SILDebugScope(ALoc); const SILDebugScope *Scope = new (IGM.getSILModule()) SILDebugScope(ALoc);
emitFunction(Scope, Fn, SILFunctionTypeRepresentation::Thin, SILTy); emitFunction(Scope, Fn, SILFunctionTypeRepresentation::Thin, SILTy);
setCurrentLoc(Builder, Scope); /// Reusing the current file would be wrong: An objc thunk, for example, could
/// be triggered from any random location. Use a placeholder name instead.
setCurrentLoc(Builder, Scope, ALoc);
} }
void IRGenDebugInfoImpl::emitVariableDeclaration( void IRGenDebugInfoImpl::emitVariableDeclaration(

View File

@@ -457,7 +457,7 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
auto fn = existingFn; auto fn = existingFn;
// TODO: use the correct SILLocation from module. // TODO: use the correct SILLocation from module.
SILLocation loc = getCompilerGeneratedLocation(); SILLocation loc = RegularLocation::getAutoGeneratedLocation();
// If we have an existing function, verify that the types match up. // If we have an existing function, verify that the types match up.
if (fn) { if (fn) {

View File

@@ -70,7 +70,7 @@ func foo(_ a: Int64, _ b: Int64) -> Int64 {
// CHECK-DAG: ![[FILE_CWD:[0-9]+]] = !DIFile(filename: "{{.*}}DebugInfo/basic.swift", directory: "{{.*}}") // CHECK-DAG: ![[FILE_CWD:[0-9]+]] = !DIFile(filename: "{{.*}}DebugInfo/basic.swift", directory: "{{.*}}")
// CHECK-DAG: ![[MAINFILE:[0-9]+]] = !DIFile(filename: "basic.swift", directory: "{{.*}}DebugInfo") // CHECK-DAG: ![[MAINFILE:[0-9]+]] = !DIFile(filename: "basic.swift", directory: "{{.*}}DebugInfo")
// CHECK-DAG: !DICompileUnit(language: DW_LANG_Swift, file: ![[FILE_CWD]],{{.*}} producer: "{{.*}}Swift version{{.*}},{{.*}} flags: "{{[^"]*}}-emit-ir // CHECK-DAG: !DICompileUnit(language: DW_LANG_Swift, file: ![[FILE_CWD]],{{.*}} producer: "{{.*}}Swift version{{.*}},{{.*}} flags: "{{[^"]*}}-emit-ir
// CHECK-DAG: !DISubprogram(name: "main" // CHECK-DAG: !DISubprogram(name: "main", {{.*}}file: ![[MAINFILE]],
// Function type for foo. // Function type for foo.
// CHECK-DAG: ![[FOOTYPE]] = !DISubroutineType(types: ![[PARAMTYPES:[0-9]+]]) // CHECK-DAG: ![[FOOTYPE]] = !DISubroutineType(types: ![[PARAMTYPES:[0-9]+]])

View File

@@ -16,8 +16,11 @@ let i = foo.foo(-, x: y)
// CHECK: define {{.*}}@"$Ss5Int64VABIyByd_A2BIgyd_TR" // CHECK: define {{.*}}@"$Ss5Int64VABIyByd_A2BIgyd_TR"
// CHECK-NOT: ret // CHECK-NOT: ret
// CHECK: call {{.*}}, !dbg ![[LOC:.*]] // CHECK: call {{.*}}, !dbg ![[LOC:.*]]
// CHECK: ![[FILE:[0-9]+]] = !DIFile(filename: "<compiler-generated>", directory: "")
// CHECK: ![[THUNK:.*]] = distinct !DISubprogram(linkageName: "$Ss5Int64VABIyByd_A2BIgyd_TR" // CHECK: ![[THUNK:.*]] = distinct !DISubprogram(linkageName: "$Ss5Int64VABIyByd_A2BIgyd_TR"
// CHECK-SAME: file: ![[FILE]]
// CHECK-NOT: line: // CHECK-NOT: line:
// CHECK-SAME: flags: DIFlagArtificial
// CHECK-SAME: ){{$}} // CHECK-SAME: ){{$}}
// CHECK: ![[LOC]] = !DILocation(line: 0, scope: ![[THUNK]]) // CHECK: ![[LOC]] = !DILocation(line: 0, scope: ![[THUNK]])