Skip to content

Commit 203f906

Browse files
authored
Serialize/Deserialize source locations for instructions (swiftlang#77281)
This commit adds support for serializing and deserializing source locations for instructions.
1 parent b5e8cfb commit 203f906

File tree

11 files changed

+176
-10
lines changed

11 files changed

+176
-10
lines changed

include/swift/SIL/SILLocation.h

+13-9
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,9 @@ class SILLocation {
5252
/// Describes a position in a source file by explicitly storing the file name,
5353
/// line and column.
5454
///
55-
/// This is used for parsed locations from a SIL file, for
55+
/// This is used for parsed locations from SIL and swiftmodule files, for
5656
/// "-sil-based-debuginfo" (see SILDebugInfoGenerator) and for the
5757
/// "compiler-generated" singleton location.
58-
/// In future we might also use it for de-serialized locations from a
59-
/// swiftmodule file.
6058
struct FilenameAndLocation : public SILAllocated<FilenameAndLocation> {
6159
unsigned line;
6260
uint16_t column;
@@ -263,6 +261,12 @@ class SILLocation {
263261
assert(filePos && !filePos->filename.empty());
264262
}
265263

264+
SILLocation(FilenameAndLocation *filePos, LocationKind K, bool Implicit)
265+
: storage(filePos), kindAndFlags(K, FilenameAndLocationKind) {
266+
assert(filePos && !filePos->filename.empty());
267+
kindAndFlags.fields.implicit = Implicit;
268+
}
269+
266270
// It is okay to pass a nullptr, but preferably, a null-location should be
267271
// created with `invalid()`.
268272
SILLocation(ASTNodeTy Node, LocationKind K)
@@ -550,8 +554,8 @@ class RegularLocation : public SILLocation {
550554
bool isForDebugOnly = true);
551555
RegularLocation(SourceLoc L, bool Implicit = true)
552556
: SILLocation(L, RegularKind, Implicit) {}
553-
RegularLocation(FilenameAndLocation *filePos)
554-
: SILLocation(filePos, RegularKind) {}
557+
RegularLocation(FilenameAndLocation *filePos, bool Implicit = false)
558+
: SILLocation(filePos, RegularKind, Implicit) {}
555559

556560
/// Convert \p loc to a RegularLocation.
557561
explicit RegularLocation(SILLocation loc) : SILLocation(loc, RegularKind) {}
@@ -619,8 +623,8 @@ class ReturnLocation : public SILLocation {
619623
/// Construct the return location for a constructor or a destructor.
620624
ReturnLocation(BraceStmt *BS);
621625

622-
ReturnLocation(FilenameAndLocation *filePos)
623-
: SILLocation(filePos, ReturnKind) {}
626+
ReturnLocation(FilenameAndLocation *filePos, bool Implicit = false)
627+
: SILLocation(filePos, ReturnKind, Implicit) {}
624628

625629
static bool isKind(const SILLocation& L) {
626630
return L.getKind() == ReturnKind;
@@ -640,8 +644,8 @@ class ImplicitReturnLocation : public SILLocation {
640644

641645
ImplicitReturnLocation(AbstractFunctionDecl *AFD);
642646

643-
ImplicitReturnLocation(FilenameAndLocation *filePos)
644-
: SILLocation(filePos, ImplicitReturnKind) {}
647+
ImplicitReturnLocation(FilenameAndLocation *filePos, bool Implicit = false)
648+
: SILLocation(filePos, ImplicitReturnKind, Implicit) {}
645649

646650
/// Convert \p loc to an ImplicitReturnLocation.
647651
explicit ImplicitReturnLocation(SILLocation Loc);

lib/SIL/IR/SILLocation.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ SourceLoc SILLocation::getStartSourceLoc() const {
137137
return SourceLoc();
138138
if (isSILFile())
139139
return storage.sourceLoc;
140+
if (getStorageKind() == FilenameAndLocationKind)
141+
return SourceLoc();
140142
return getStartSourceLoc(getPrimaryASTNode());
141143
}
142144

@@ -158,6 +160,8 @@ SourceLoc SILLocation::getEndSourceLoc() const {
158160
return SourceLoc();
159161
if (isSILFile())
160162
return storage.sourceLoc;
163+
if (getStorageKind() == FilenameAndLocationKind)
164+
return SourceLoc();
161165
return getEndSourceLoc(getPrimaryASTNode());
162166
}
163167

lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,15 @@ static bool diagnoseUnreachableBlock(
993993
if (Loc.is<ImplicitReturnLocation>() || Loc.isAutoGenerated())
994994
return false;
995995

996+
// Without debug info serialization, source locations are deserialized as
997+
// implicit by default and as a result this diagnostic is never produced on
998+
// deserialized code. With support for serializing debug info/source
999+
// locations, the implicit flag is deserialized properly . However, this
1000+
// creates new diagnostic warnings in many tests. Until these tests are
1001+
// fixed, we suppress these warnings to match existing behavior.
1002+
if (Loc.isFilenameAndLocation())
1003+
continue;
1004+
9961005
// Check if the instruction corresponds to user-written code, also make
9971006
// sure we don't report an error twice for the same instruction.
9981007
if (isUserCode(&*I) && !State->BlocksWithErrors.contains(&B)) {

lib/Serialization/DeserializeSIL.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,44 @@ SILDeserializer::readNextRecord(SmallVectorImpl<uint64_t> &scratch) {
394394
return maybeKind;
395395
}
396396

397+
std::optional<SILLocation> SILDeserializer::readLoc(unsigned kind,
398+
SmallVectorImpl<uint64_t> &scratch) {
399+
unsigned LocationKind, Implicit = 0;
400+
SILLocation::FilenameAndLocation *FNameLoc = nullptr;
401+
// Each SourceLoc opaque pointer is serialized once. Successive appearences
402+
// are serialized as references to earlier serializations, with LocID as the
403+
// indexing key
404+
if (kind == SIL_SOURCE_LOC_REF) {
405+
ValueID LocID;
406+
SourceLocRefLayout::readRecord(scratch, LocID, LocationKind, Implicit);
407+
if (LocID == 0)
408+
return std::optional<SILLocation>();
409+
FNameLoc = ParsedLocs[LocID - 1];
410+
} else {
411+
ValueID Row = 0, Col = 0, FNameID = 0;
412+
SourceLocLayout::readRecord(scratch, Row, Col, FNameID, LocationKind, Implicit);
413+
414+
415+
FNameLoc = SILLocation::FilenameAndLocation::alloc(
416+
Row, Col, MF->getIdentifierText(FNameID), SILMod);
417+
418+
ParsedLocs.push_back(FNameLoc);
419+
}
420+
421+
switch(LocationKind) {
422+
case SILLocation::ReturnKind:
423+
return ReturnLocation(FNameLoc, Implicit);
424+
case SILLocation::ImplicitReturnKind:
425+
return ImplicitReturnLocation(FNameLoc, Implicit);
426+
case SILLocation::InlinedKind:
427+
case SILLocation::MandatoryInlinedKind:
428+
case SILLocation::CleanupKind:
429+
case SILLocation::ArtificialUnreachableKind:
430+
case SILLocation::RegularKind:
431+
return RegularLocation(FNameLoc, Implicit);
432+
}
433+
}
434+
397435
llvm::Expected<const SILDebugScope *>
398436
SILDeserializer::readDebugScopes(SILFunction *F,
399437
SmallVectorImpl<uint64_t> &scratch,
@@ -1066,6 +1104,7 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
10661104
BlocksByID.clear();
10671105
UndefinedBlocks.clear();
10681106
ParsedScopes.clear();
1107+
ParsedLocs.clear();
10691108

10701109
// The first two IDs are reserved for SILUndef.
10711110
LastValueID = 1;
@@ -1095,6 +1134,9 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
10951134
isFirstScope = false;
10961135
}
10971136
Builder.setCurrentDebugScope(Scope);
1137+
} else if (kind == SIL_SOURCE_LOC || kind == SIL_SOURCE_LOC_REF) {
1138+
auto Loc = readLoc(kind, scratch);
1139+
Builder.applyDebugLocOverride(Loc);
10981140
} else {
10991141
// If CurrentBB is empty, just return fn. The code in readSILInstruction
11001142
// assumes that such a situation means that fn is a declaration. Thus it

lib/Serialization/DeserializeSIL.h

+3
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ namespace swift {
150150
readDebugScopes(SILFunction *F, SmallVectorImpl<uint64_t> &scratch,
151151
SILBuilder &Builder, unsigned kind);
152152
llvm::Expected<unsigned> readNextRecord(SmallVectorImpl<uint64_t> &scratch);
153+
std::optional<SILLocation> readLoc(unsigned kind, SmallVectorImpl<uint64_t> &scratch);
154+
153155
llvm::DenseMap<unsigned, const SILDebugScope *> ParsedScopes;
156+
llvm::SmallVector<SILLocation::FilenameAndLocation *> ParsedLocs;
154157

155158
SILFunction *getFuncForReference(StringRef Name, SILType Ty, TypeExpansionContext context);
156159
SILFunction *getFuncForReference(StringRef Name, bool forDebugScope = false);

lib/Serialization/ModuleFormat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 907; // TypeAliasType change
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 908; // debug scopes and source locs
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

lib/Serialization/SILFormat.h

+18
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ namespace sil_block {
178178
SIL_VALUES,
179179
SIL_DEBUG_SCOPE,
180180
SIL_DEBUG_SCOPE_REF,
181+
SIL_SOURCE_LOC,
182+
SIL_SOURCE_LOC_REF
181183
};
182184

183185
using SILInstNoOperandLayout = BCRecordLayout<
@@ -310,6 +312,22 @@ namespace sil_block {
310312
SILTypeCategoryField
311313
>;
312314

315+
using SourceLocLayout = BCRecordLayout<
316+
SIL_SOURCE_LOC,
317+
ValueIDField,
318+
ValueIDField,
319+
ValueIDField,
320+
BCFixed<3>, /// LocationKind
321+
BCFixed<1> /// Implicit
322+
>;
323+
324+
using SourceLocRefLayout = BCRecordLayout<
325+
SIL_SOURCE_LOC_REF,
326+
ValueIDField,
327+
BCFixed<3>,
328+
BCFixed<1> /// Implicit
329+
>;
330+
313331
using SILFunctionLayout =
314332
BCRecordLayout<SIL_FUNCTION, SILLinkageField,
315333
BCFixed<1>, // transparent

lib/Serialization/Serialization.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,9 @@ void Serializer::writeBlockInfoBlock() {
960960
BLOCK_RECORD(sil_block, SIL_PACK_ELEMENT_SET);
961961
BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE);
962962
BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE_REF);
963+
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC);
964+
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC_REF);
965+
963966

964967
BLOCK(SIL_INDEX_BLOCK);
965968
BLOCK_RECORD(sil_index_block, SIL_FUNC_NAMES);

lib/Serialization/SerializeSIL.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ namespace {
162162
using DebugScopeID = DeclID;
163163
using DebugScopeIDField = DeclIDField;
164164

165+
using LocationID = DeclID;
166+
using LocationIDField = DeclIDField;
167+
165168
Serializer &S;
166169

167170
llvm::BitstreamWriter &Out;
@@ -226,6 +229,7 @@ namespace {
226229

227230
llvm::DenseMap<PointerUnion<const SILDebugScope *, SILFunction *>, DeclID>
228231
DebugScopeMap;
232+
llvm::DenseMap<const void *, unsigned> SourceLocMap;
229233

230234
/// Give each SILBasicBlock a unique ID.
231235
llvm::DenseMap<const SILBasicBlock *, unsigned> BasicBlockMap;
@@ -299,6 +303,7 @@ namespace {
299303

300304
/// Serialize and write SILDebugScope graph in post order.
301305
void writeDebugScopes(const SILDebugScope *Scope, const SourceManager &SM);
306+
void writeSourceLoc(SILLocation SLoc, const SourceManager &SM);
302307

303308
void writeNoOperandLayout(const SILInstruction *I) {
304309
unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code];
@@ -600,6 +605,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
600605
}
601606

602607
DebugScopeMap.clear();
608+
SourceLocMap.clear();
603609

604610
if (SerializeDebugInfoSIL)
605611
writeDebugScopes(F.getDebugScope(), F.getModule().getSourceManager());
@@ -697,6 +703,9 @@ void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) {
697703
writeDebugScopes(Prev, SM);
698704
}
699705
}
706+
if (SerializeDebugInfoSIL) {
707+
writeSourceLoc(SI.getLoc(), SM);
708+
}
700709

701710
writeSILInstruction(SI);
702711
}
@@ -3074,6 +3083,51 @@ void SILSerializer::writeSILProperty(const SILProperty &prop) {
30743083
componentValues);
30753084
}
30763085

3086+
void SILSerializer::writeSourceLoc(SILLocation Loc, const SourceManager &SM) {
3087+
auto SLoc = Loc.getSourceLoc();
3088+
auto OpaquePtr = SLoc.getOpaquePointerValue();
3089+
uint8_t LocationKind;
3090+
switch(Loc.getKind()) {
3091+
case SILLocation::ReturnKind:
3092+
LocationKind = SILLocation::ReturnKind;
3093+
break;
3094+
case SILLocation::ImplicitReturnKind:
3095+
LocationKind = SILLocation::ImplicitReturnKind;
3096+
break;
3097+
case SILLocation::InlinedKind:
3098+
case SILLocation::MandatoryInlinedKind:
3099+
case SILLocation::CleanupKind:
3100+
case SILLocation::ArtificialUnreachableKind:
3101+
case SILLocation::RegularKind:
3102+
LocationKind = SILLocation::RegularKind;
3103+
break;
3104+
}
3105+
3106+
if (SourceLocMap.find(OpaquePtr) != SourceLocMap.end()) {
3107+
SourceLocRefLayout::emitRecord(Out, ScratchRecord,
3108+
SILAbbrCodes[SourceLocRefLayout::Code],
3109+
SourceLocMap[OpaquePtr], LocationKind, (unsigned)Loc.isImplicit());
3110+
return;
3111+
}
3112+
3113+
ValueID Row = 0;
3114+
ValueID Column = 0;
3115+
ValueID FNameID = 0;
3116+
3117+
if (!SLoc.isValid()) {
3118+
//emit empty source loc
3119+
SourceLocRefLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SourceLocRefLayout::Code], 0, 0, (unsigned)0);
3120+
return;
3121+
}
3122+
3123+
std::tie(Row, Column) = SM.getPresumedLineAndColumnForLoc(SLoc);
3124+
FNameID = S.addUniquedStringRef(SM.getDisplayNameForLoc(SLoc));
3125+
SourceLocMap.insert({OpaquePtr, SourceLocMap.size() + 1});
3126+
SourceLocLayout::emitRecord(Out, ScratchRecord,
3127+
SILAbbrCodes[SourceLocLayout::Code], Row, Column,
3128+
FNameID, LocationKind, (unsigned)Loc.isImplicit());
3129+
}
3130+
30773131
void SILSerializer::writeDebugScopes(const SILDebugScope *Scope,
30783132
const SourceManager &SM) {
30793133

@@ -3387,6 +3441,8 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) {
33873441
registerSILAbbr<DifferentiabilityWitnessLayout>();
33883442
registerSILAbbr<SILDebugScopeLayout>();
33893443
registerSILAbbr<SILDebugScopeRefLayout>();
3444+
registerSILAbbr<SourceLocLayout>();
3445+
registerSILAbbr<SourceLocRefLayout>();
33903446

33913447
// Write out VTables first because it may require serializations of
33923448
// non-transparent SILFunctions (body is not needed).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@_transparent
2+
public func foo(x: UInt64) -> UInt64 {
3+
if (x > 100) {
4+
return 100
5+
}
6+
7+
return 1
8+
}

test/Serialization/source-loc.swift

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_source_loc.swift -experimental-serialize-debug-info -O -g
3+
// RUN: llvm-bcanalyzer %t/def_source_loc.swiftmodule | %FileCheck %s --check-prefix=SIL
4+
// RUN: %target-swift-frontend -module-name source_loc -g -emit-sil -I %t %s | %FileCheck %s
5+
6+
// SIL-NOT: UnknownCode
7+
8+
import def_source_loc
9+
10+
let _ = foo(x: 100)
11+
12+
//CHECK: {{.*integer_literal.*}} loc "{{.*}}def_source_loc.swift":3:13
13+
//CHECK: {{.*struct_extract.*}} loc "{{.*}}def_source_loc.swift":3:11
14+
//CHECK: {{.*builtin "cmp_ult_Int64".*}} loc "{{.*}}def_source_loc.swift":3:11
15+
//CHECK: {{.*cond_br.*}} loc "{{.*}}def_source_loc.swift":3:11
16+
//CHECK: {{.*integer_literal.*}} 1, loc "{{.*}}def_source_loc.swift":7:12
17+
//CHECK: {{.*struct \$UInt64.*}} loc "{{.*}}def_source_loc.swift":7:12
18+
//CHECK: {{.*br.*}} loc "{{.*}}def_source_loc.swift":7:5
19+
//CHECK: {{.*return.*}} loc "{{.*}}def_source_loc.swift":8:2

0 commit comments

Comments
 (0)