Skip to content

Commit 500187c

Browse files
authored
Add support for serializing debug_value instructions (#78056)
This patch adds support for serialization of debug value instructions. Enablement is currently gated behind the -experimental-serialize-debug-info flag. Previously, debug_value instructions were lost during serialization. This made it harder to debug cross module inlined functions.
1 parent 2775182 commit 500187c

File tree

11 files changed

+320
-20
lines changed

11 files changed

+320
-20
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ class SILBuilder {
10651065
SILLocation Loc, SILValue src, SILDebugVariable Var,
10661066
PoisonRefs_t poisonRefs = DontPoisonRefs,
10671067
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,
1068-
bool trace = false);
1068+
bool trace = false, bool overrideLoc = true);
10691069
DebugValueInst *createDebugValueAddr(
10701070
SILLocation Loc, SILValue src, SILDebugVariable Var,
10711071
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,

lib/IRGen/IRGenSIL.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,11 @@ class IRGenSILFunction :
965965
bool shouldShadowVariable(SILDebugVariable varInfo, bool isAnonymous) {
966966
return !IGM.IRGen.Opts.DisableDebuggerShadowCopies
967967
&& !IGM.IRGen.Opts.shouldOptimize()
968+
// Shadow copies are only emitted at -Onone, but a deserialized function
969+
// might have been already optimized, so ignore those.
970+
&& !CurSILFn->wasDeserializedCanonical()
971+
&& (!CurSILFn->isSpecialization() ||
972+
!CurSILFn->getSpecializationInfo()->getParent()->wasDeserializedCanonical())
968973
&& !isAnonymous;
969974
}
970975

lib/SIL/IR/SILBuilder.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,17 +638,24 @@ DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
638638
SILDebugVariable Var,
639639
PoisonRefs_t poisonRefs,
640640
UsesMoveableValueDebugInfo_t moved,
641-
bool trace) {
641+
bool trace, bool overrideLoc) {
642642
if (shouldDropVariable(Var, Loc))
643643
return nullptr;
644644

645645
llvm::SmallString<4> Name;
646646

647-
// Debug location overrides cannot apply to debug value instructions.
648-
DebugLocOverrideRAII LocOverride{*this, std::nullopt};
649-
return insert(DebugValueInst::create(
650-
getSILDebugLocation(Loc, true), src, getModule(),
651-
*substituteAnonymousArgs(Name, Var, Loc), poisonRefs, moved, trace));
647+
SILDebugLocation DebugLoc;
648+
if (overrideLoc) {
649+
// Debug location overrides cannot apply to debug value instructions.
650+
DebugLocOverrideRAII LocOverride{*this, std::nullopt};
651+
DebugLoc = getSILDebugLocation(Loc, true);
652+
} else {
653+
DebugLoc = getSILDebugLocation(Loc, true);
654+
}
655+
656+
return insert(DebugValueInst::create(DebugLoc, src, getModule(),
657+
*substituteAnonymousArgs(Name, Var, Loc),
658+
poisonRefs, moved, trace));
652659
}
653660

654661
DebugValueInst *SILBuilder::createDebugValueAddr(

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@ bool SILParser::parseSILDebugInfoExpression(SILDebugInfoExpression &DIExpr) {
16031603
P.consumeToken();
16041604
IsNegative = true;
16051605
}
1606-
int64_t Val;
1606+
uint64_t Val;
16071607
if (parseInteger(Val, diag::sil_invalid_constant))
16081608
return true;
16091609
if (IsNegative)

lib/Serialization/DeserializeSIL.cpp

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
10561056

10571057
GenericEnvironment *genericEnv = nullptr;
10581058
// Generic signatures are stored for declarations as well in a debug context.
1059-
if (!declarationOnly || onlyReferencedByDebugInfo)
1059+
if (!declarationOnly || onlyReferencedByDebugInfo || genericSigID)
10601060
genericEnv = MF->getGenericSignature(genericSigID).getGenericEnvironment();
10611061

10621062
// If the next entry is the end of the block, then this function has
@@ -1066,8 +1066,8 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
10661066
return maybeEntry.takeError();
10671067
entry = maybeEntry.get();
10681068
bool isEmptyFunction = (entry.Kind == llvm::BitstreamEntry::EndBlock);
1069-
assert((!isEmptyFunction || !genericEnv || onlyReferencedByDebugInfo) &&
1070-
"generic environment without body?!");
1069+
assert((!isEmptyFunction || !genericEnv || onlyReferencedByDebugInfo ||
1070+
genericSigID) && "generic environment without body?!");
10711071

10721072
// Remember this in our cache in case it's a recursive function.
10731073
// Increase the reference count to keep it alive.
@@ -1133,7 +1133,8 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
11331133

11341134
auto Scope = maybeScope.get();
11351135
if (isFirstScope) {
1136-
fn->setDebugScope(Scope);
1136+
if (!fn->getDebugScope() || fn->getDebugScope()->getLoc().isAutoGenerated())
1137+
fn->setDebugScope(Scope);
11371138
isFirstScope = false;
11381139
}
11391140
Builder.setCurrentDebugScope(Scope);
@@ -1421,6 +1422,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
14211422
switch (RecordKind) {
14221423
default:
14231424
llvm_unreachable("Record kind for a SIL instruction is not supported.");
1425+
case SIL_DEBUG_VALUE_DELIMITER:
1426+
return false;
14241427
case SIL_ONE_VALUE_ONE_OPERAND:
14251428
SILOneValueOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
14261429
ValID, TyID, TyCategory,
@@ -1593,20 +1596,121 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
15931596
SILThunkLayout::readRecord(scratch, Attr, TyID, TyCategory, ValID, SubID);
15941597
RawOpCode = unsigned(SILInstructionKind::ThunkInst);
15951598
break;
1599+
1600+
case SIL_DEBUG_VALUE:
1601+
SILDebugValueLayout::readRecord(scratch, TyCategory, TyCategory2, Attr,
1602+
ListOfValues);
1603+
RawOpCode = (unsigned)SILInstructionKind::DebugValueInst;
1604+
1605+
break;
15961606
}
15971607

15981608
// FIXME: validate
15991609
SILInstructionKind OpCode = (SILInstructionKind) RawOpCode;
16001610

16011611
SILInstruction *ResultInst;
16021612
switch (OpCode) {
1603-
case SILInstructionKind::DebugValueInst:
16041613
case SILInstructionKind::DebugStepInst:
16051614
case SILInstructionKind::SpecifyTestInst:
16061615
case SILInstructionKind::AllocPackMetadataInst:
16071616
case SILInstructionKind::DeallocPackMetadataInst:
16081617
llvm_unreachable("not supported");
16091618

1619+
case SILInstructionKind::DebugValueInst: {
1620+
assert(ListOfValues.size() >= 2 && "Unexpected number of values");
1621+
SILValue Value =
1622+
getLocalValue(Fn, ListOfValues[0],
1623+
getSILType(MF->getType(ListOfValues[1]),
1624+
(SILValueCategory)TyCategory, Fn));
1625+
1626+
auto PoisonRefs = PoisonRefs_t(Attr & 0x1);
1627+
auto UsesMoveableValDebugInfo =
1628+
UsesMoveableValueDebugInfo_t((Attr >> 1) & 0x1);
1629+
auto HasTrace = (Attr >> 2) & 0x1;
1630+
1631+
bool HaveDebugVar = (Attr >> 3) & 0x1;
1632+
bool HasLoc = false;
1633+
1634+
SILDebugVariable DebugVar;
1635+
if (HaveDebugVar) {
1636+
assert(ListOfValues.size() >= 4 && "Unexpected number of values");
1637+
bool IsLet = (Attr >> 4) & 0x1;
1638+
unsigned IsDenseMapSingleton = (Attr >> 5) & 0x3;
1639+
bool HasType = (Attr >> 7) & 0x1;
1640+
bool HasScope = (Attr >> 8) & 0x1;
1641+
HasLoc = (Attr >> 9) & 0x1;
1642+
1643+
auto VarName = MF->getIdentifierText(ListOfValues[2]);
1644+
auto ArgNo = ListOfValues[3];
1645+
std::optional<SILType> Type;
1646+
1647+
unsigned I = 4;
1648+
unsigned Row, Col;
1649+
StringRef FileName;
1650+
std::optional<SILLocation> Loc;
1651+
if (HasType) {
1652+
Type = getSILType(MF->getType(ListOfValues[I++]),
1653+
(SILValueCategory)TyCategory2, Fn);
1654+
}
1655+
1656+
if (HasLoc) {
1657+
Row = ListOfValues[I++];
1658+
Col = ListOfValues[I++];
1659+
FileName = MF->getIdentifierText(ListOfValues[I++]);
1660+
Loc = RegularLocation(SILLocation::FilenameAndLocation::alloc(
1661+
Row, Col, FileName, Fn->getModule()));
1662+
}
1663+
1664+
SILDebugInfoExpression Expressions;
1665+
while (I < ListOfValues.size()) {
1666+
using DIExpr = SILDIExprElement;
1667+
SILDIExprElement::Kind Kind = (SILDIExprElement::Kind)ListOfValues[I++];
1668+
switch (Kind) {
1669+
case DIExpr::OperatorKind:
1670+
Expressions.push_back(
1671+
DIExpr::createOperator((SILDIExprOperator)ListOfValues[I++]));
1672+
break;
1673+
case DIExpr::DeclKind:
1674+
Expressions.push_back(
1675+
DIExpr::createDecl(MF->getDecl(ListOfValues[I++])));
1676+
break;
1677+
case DIExpr::ConstIntKind: {
1678+
auto Str = MF->getIdentifierText(ListOfValues[I++]);
1679+
APInt Int;
1680+
Str.getAsInteger(10, Int);
1681+
Expressions.push_back(DIExpr::createConstInt(Int.getLimitedValue()));
1682+
break;
1683+
}
1684+
case SILDIExprElement::Kind::TypeKind:
1685+
Expressions.push_back(
1686+
DIExpr::createType(MF->getType(ListOfValues[I++])));
1687+
break;
1688+
}
1689+
}
1690+
1691+
const SILDebugScope *Scope = nullptr;
1692+
if (HasScope) {
1693+
SmallVector<uint64_t, 64> scratch;
1694+
auto maybeKind = readNextRecord(scratch);
1695+
if (!maybeKind) MF->fatal(maybeKind.takeError());
1696+
auto maybeScope = readDebugScopes(Fn, scratch, Builder, maybeKind.get());
1697+
if (!maybeScope) MF->fatal(maybeScope.takeError());
1698+
Scope = maybeScope.get();
1699+
}
1700+
1701+
DebugVar = SILDebugVariable(
1702+
VarName, IsLet, ArgNo, Type, Loc, Scope,
1703+
llvm::ArrayRef<SILDIExprElement>(Expressions.element_begin(),
1704+
Expressions.element_end()));
1705+
DebugVar.isDenseMapSingleton = IsDenseMapSingleton;
1706+
}
1707+
1708+
ResultInst =
1709+
Builder.createDebugValue(Loc, Value, DebugVar, PoisonRefs,
1710+
UsesMoveableValDebugInfo, HasTrace, !HasLoc);
1711+
1712+
break;
1713+
}
16101714
case SILInstructionKind::AllocBoxInst: {
16111715
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
16121716
auto hasDynamicLifetime = HasDynamicLifetime_t(Attr & 0x1);

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
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 = 922; // function type isolation - caller
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 923; // debug values
6262

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

lib/Serialization/SILFormat.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ namespace sil_block {
179179
SIL_DEBUG_SCOPE,
180180
SIL_DEBUG_SCOPE_REF,
181181
SIL_SOURCE_LOC,
182-
SIL_SOURCE_LOC_REF
182+
SIL_SOURCE_LOC_REF,
183+
SIL_DEBUG_VALUE_DELIMITER,
184+
SIL_DEBUG_VALUE,
183185
};
184186

185187
using SILInstNoOperandLayout = BCRecordLayout<
@@ -312,6 +314,22 @@ namespace sil_block {
312314
SILTypeCategoryField
313315
>;
314316

317+
using SILDebugValueLayout = BCRecordLayout<
318+
SIL_DEBUG_VALUE,
319+
320+
SILTypeCategoryField, /// operand type category
321+
SILTypeCategoryField, /// debug var type category
322+
BCFixed<11>, /// poison, movableValueDebuginfo, trace,
323+
/// hasDebugVar, isLet, isDenseMapSingleton(two
324+
/// bits), hasSource, hasLoc, hasExpr
325+
BCArray<ValueIDField> /// operand info: operand, type, debug var info:
326+
/// name, argno, optional stuff: typeid
327+
>;
328+
329+
using DebugValueDelimiterLayout = BCRecordLayout<
330+
SIL_DEBUG_VALUE_DELIMITER
331+
>;
332+
315333
using SourceLocLayout = BCRecordLayout<
316334
SIL_SOURCE_LOC,
317335
ValueIDField,

lib/Serialization/Serialization.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,8 @@ void Serializer::writeBlockInfoBlock() {
964964
BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE_REF);
965965
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC);
966966
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC_REF);
967+
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE);
968+
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE_DELIMITER);
967969

968970

969971
BLOCK(SIL_INDEX_BLOCK);

0 commit comments

Comments
 (0)