Skip to content

Add support for serializing debug_value instructions #78056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,7 @@ class SILBuilder {
SILLocation Loc, SILValue src, SILDebugVariable Var,
PoisonRefs_t poisonRefs = DontPoisonRefs,
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,
bool trace = false);
bool trace = false, bool overrideLoc = true);
DebugValueInst *createDebugValueAddr(
SILLocation Loc, SILValue src, SILDebugVariable Var,
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,
Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,11 @@ class IRGenSILFunction :
bool shouldShadowVariable(SILDebugVariable varInfo, bool isAnonymous) {
return !IGM.IRGen.Opts.DisableDebuggerShadowCopies
&& !IGM.IRGen.Opts.shouldOptimize()
// Shadow copies are only emitted at -Onone, but a deserialized function
// might have been already optimized, so ignore those.
&& !CurSILFn->wasDeserializedCanonical()
&& (!CurSILFn->isSpecialization() ||
!CurSILFn->getSpecializationInfo()->getParent()->wasDeserializedCanonical())
&& !isAnonymous;
}

Expand Down
19 changes: 13 additions & 6 deletions lib/SIL/IR/SILBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,17 +638,24 @@ DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
SILDebugVariable Var,
PoisonRefs_t poisonRefs,
UsesMoveableValueDebugInfo_t moved,
bool trace) {
bool trace, bool overrideLoc) {
if (shouldDropVariable(Var, Loc))
return nullptr;

llvm::SmallString<4> Name;

// Debug location overrides cannot apply to debug value instructions.
DebugLocOverrideRAII LocOverride{*this, std::nullopt};
return insert(DebugValueInst::create(
getSILDebugLocation(Loc, true), src, getModule(),
*substituteAnonymousArgs(Name, Var, Loc), poisonRefs, moved, trace));
SILDebugLocation DebugLoc;
if (overrideLoc) {
// Debug location overrides cannot apply to debug value instructions.
DebugLocOverrideRAII LocOverride{*this, std::nullopt};
DebugLoc = getSILDebugLocation(Loc, true);
} else {
DebugLoc = getSILDebugLocation(Loc, true);
}

return insert(DebugValueInst::create(DebugLoc, src, getModule(),
*substituteAnonymousArgs(Name, Var, Loc),
poisonRefs, moved, trace));
}

DebugValueInst *SILBuilder::createDebugValueAddr(
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1603,7 +1603,7 @@ bool SILParser::parseSILDebugInfoExpression(SILDebugInfoExpression &DIExpr) {
P.consumeToken();
IsNegative = true;
}
int64_t Val;
uint64_t Val;
if (parseInteger(Val, diag::sil_invalid_constant))
return true;
if (IsNegative)
Expand Down
114 changes: 109 additions & 5 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,7 @@ llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(

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

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

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

auto Scope = maybeScope.get();
if (isFirstScope) {
fn->setDebugScope(Scope);
if (!fn->getDebugScope() || fn->getDebugScope()->getLoc().isAutoGenerated())
fn->setDebugScope(Scope);
isFirstScope = false;
}
Builder.setCurrentDebugScope(Scope);
Expand Down Expand Up @@ -1421,6 +1422,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
switch (RecordKind) {
default:
llvm_unreachable("Record kind for a SIL instruction is not supported.");
case SIL_DEBUG_VALUE_DELIMITER:
return false;
case SIL_ONE_VALUE_ONE_OPERAND:
SILOneValueOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
ValID, TyID, TyCategory,
Expand Down Expand Up @@ -1593,20 +1596,121 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
SILThunkLayout::readRecord(scratch, Attr, TyID, TyCategory, ValID, SubID);
RawOpCode = unsigned(SILInstructionKind::ThunkInst);
break;

case SIL_DEBUG_VALUE:
SILDebugValueLayout::readRecord(scratch, TyCategory, TyCategory2, Attr,
ListOfValues);
RawOpCode = (unsigned)SILInstructionKind::DebugValueInst;

break;
}

// FIXME: validate
SILInstructionKind OpCode = (SILInstructionKind) RawOpCode;

SILInstruction *ResultInst;
switch (OpCode) {
case SILInstructionKind::DebugValueInst:
case SILInstructionKind::DebugStepInst:
case SILInstructionKind::SpecifyTestInst:
case SILInstructionKind::AllocPackMetadataInst:
case SILInstructionKind::DeallocPackMetadataInst:
llvm_unreachable("not supported");

case SILInstructionKind::DebugValueInst: {
assert(ListOfValues.size() >= 2 && "Unexpected number of values");
SILValue Value =
getLocalValue(Fn, ListOfValues[0],
getSILType(MF->getType(ListOfValues[1]),
(SILValueCategory)TyCategory, Fn));

auto PoisonRefs = PoisonRefs_t(Attr & 0x1);
auto UsesMoveableValDebugInfo =
UsesMoveableValueDebugInfo_t((Attr >> 1) & 0x1);
auto HasTrace = (Attr >> 2) & 0x1;

bool HaveDebugVar = (Attr >> 3) & 0x1;
bool HasLoc = false;

SILDebugVariable DebugVar;
if (HaveDebugVar) {
assert(ListOfValues.size() >= 4 && "Unexpected number of values");
bool IsLet = (Attr >> 4) & 0x1;
unsigned IsDenseMapSingleton = (Attr >> 5) & 0x3;
bool HasType = (Attr >> 7) & 0x1;
bool HasScope = (Attr >> 8) & 0x1;
HasLoc = (Attr >> 9) & 0x1;

auto VarName = MF->getIdentifierText(ListOfValues[2]);
auto ArgNo = ListOfValues[3];
std::optional<SILType> Type;

unsigned I = 4;
unsigned Row, Col;
StringRef FileName;
std::optional<SILLocation> Loc;
if (HasType) {
Type = getSILType(MF->getType(ListOfValues[I++]),
(SILValueCategory)TyCategory2, Fn);
}

if (HasLoc) {
Row = ListOfValues[I++];
Col = ListOfValues[I++];
FileName = MF->getIdentifierText(ListOfValues[I++]);
Loc = RegularLocation(SILLocation::FilenameAndLocation::alloc(
Row, Col, FileName, Fn->getModule()));
}

SILDebugInfoExpression Expressions;
while (I < ListOfValues.size()) {
using DIExpr = SILDIExprElement;
SILDIExprElement::Kind Kind = (SILDIExprElement::Kind)ListOfValues[I++];
switch (Kind) {
case DIExpr::OperatorKind:
Expressions.push_back(
DIExpr::createOperator((SILDIExprOperator)ListOfValues[I++]));
break;
case DIExpr::DeclKind:
Expressions.push_back(
DIExpr::createDecl(MF->getDecl(ListOfValues[I++])));
break;
case DIExpr::ConstIntKind: {
auto Str = MF->getIdentifierText(ListOfValues[I++]);
APInt Int;
Str.getAsInteger(10, Int);
Expressions.push_back(DIExpr::createConstInt(Int.getLimitedValue()));
break;
}
case SILDIExprElement::Kind::TypeKind:
Expressions.push_back(
DIExpr::createType(MF->getType(ListOfValues[I++])));
break;
}
}

const SILDebugScope *Scope = nullptr;
if (HasScope) {
SmallVector<uint64_t, 64> scratch;
auto maybeKind = readNextRecord(scratch);
if (!maybeKind) MF->fatal(maybeKind.takeError());
auto maybeScope = readDebugScopes(Fn, scratch, Builder, maybeKind.get());
if (!maybeScope) MF->fatal(maybeScope.takeError());
Scope = maybeScope.get();
}

DebugVar = SILDebugVariable(
VarName, IsLet, ArgNo, Type, Loc, Scope,
llvm::ArrayRef<SILDIExprElement>(Expressions.element_begin(),
Expressions.element_end()));
DebugVar.isDenseMapSingleton = IsDenseMapSingleton;
}

ResultInst =
Builder.createDebugValue(Loc, Value, DebugVar, PoisonRefs,
UsesMoveableValDebugInfo, HasTrace, !HasLoc);

break;
}
case SILInstructionKind::AllocBoxInst: {
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
auto hasDynamicLifetime = HasDynamicLifetime_t(Attr & 0x1);
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 922; // function type isolation - caller
const uint16_t SWIFTMODULE_VERSION_MINOR = 923; // debug values

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down
20 changes: 19 additions & 1 deletion lib/Serialization/SILFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ namespace sil_block {
SIL_DEBUG_SCOPE,
SIL_DEBUG_SCOPE_REF,
SIL_SOURCE_LOC,
SIL_SOURCE_LOC_REF
SIL_SOURCE_LOC_REF,
SIL_DEBUG_VALUE_DELIMITER,
SIL_DEBUG_VALUE,
};

using SILInstNoOperandLayout = BCRecordLayout<
Expand Down Expand Up @@ -312,6 +314,22 @@ namespace sil_block {
SILTypeCategoryField
>;

using SILDebugValueLayout = BCRecordLayout<
SIL_DEBUG_VALUE,

SILTypeCategoryField, /// operand type category
SILTypeCategoryField, /// debug var type category
BCFixed<11>, /// poison, movableValueDebuginfo, trace,
/// hasDebugVar, isLet, isDenseMapSingleton(two
/// bits), hasSource, hasLoc, hasExpr
BCArray<ValueIDField> /// operand info: operand, type, debug var info:
/// name, argno, optional stuff: typeid
>;

using DebugValueDelimiterLayout = BCRecordLayout<
SIL_DEBUG_VALUE_DELIMITER
>;

using SourceLocLayout = BCRecordLayout<
SIL_SOURCE_LOC,
ValueIDField,
Expand Down
2 changes: 2 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,8 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE_REF);
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC);
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC_REF);
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE);
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE_DELIMITER);


BLOCK(SIL_INDEX_BLOCK);
Expand Down
Loading