Skip to content

SIL: Only enable instruction leaks checking in the frontend's and SILOpt's modules. #39980

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 1 commit into from
Nov 2, 2021
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
6 changes: 6 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ class SILOptions {
/// Are we parsing the stdlib, i.e. -parse-stdlib?
bool ParseStdlib = false;

/// If true, check for leaking instructions when the SILModule is destructed.
///
/// Warning: this is not thread safe. It can only be enabled in case there
/// is a single SILModule in a single thread.
bool checkSILModuleLeaks = false;

/// The name of the file to which the backend should save optimization
/// records.
std::string OptRecordFile;
Expand Down
9 changes: 8 additions & 1 deletion include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,9 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
void setDebugScope(const SILDebugScope *DS);

/// Total number of created and deleted SILInstructions.
/// It is used only for collecting the compiler statistics.
///
/// Ideally, those counters would be inside SILModules to allow mutiple
/// SILModules (e.g. in different threads).
static int NumCreatedInstructions;
static int NumDeletedInstructions;

Expand Down Expand Up @@ -759,6 +761,11 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
static int getNumDeletedInstructions() {
return NumDeletedInstructions;
}

static void resetInstructionCounts() {
NumCreatedInstructions = 0;
NumDeletedInstructions = 0;
}

/// Pretty-print the value.
void dump() const;
Expand Down
4 changes: 4 additions & 0 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2065,6 +2065,10 @@ int swift::performFrontend(ArrayRef<const char *> Args,
FrontendOptions::ActionType::Immediate) {
llvm::setBugReportMsg(nullptr);
}

/// Enable leaks checking because this SILModule is the only one in the process
/// (leaks checking is not thread safe).
Invocation.getSILOptions().checkSILModuleLeaks = true;

PrettyStackTraceFrontend frontendTrace(Invocation.getLangOptions());

Expand Down
8 changes: 6 additions & 2 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,10 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
// Free the memory occupied by the SILModule.
// Execute this task in parallel to the embedding of bitcode.
auto SILModuleRelease = [&SILMod]() {
bool checkForLeaks = SILMod->getOptions().checkSILModuleLeaks;
SILMod.reset(nullptr);
SILModule::checkForLeaksAfterDestruction();
if (checkForLeaks)
SILModule::checkForLeaksAfterDestruction();
};
auto Thread = std::thread(SILModuleRelease);
// Wait for the thread to terminate.
Expand Down Expand Up @@ -1447,8 +1449,10 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
// Free the memory occupied by the SILModule.
// Execute this task in parallel to the LLVM compilation.
auto SILModuleRelease = [&SILMod]() {
bool checkForLeaks = SILMod->getOptions().checkSILModuleLeaks;
SILMod.reset(nullptr);
SILModule::checkForLeaksAfterDestruction();
if (checkForLeaks)
SILModule::checkForLeaksAfterDestruction();
};
auto releaseModuleThread = std::thread(SILModuleRelease);

Expand Down
7 changes: 7 additions & 0 deletions lib/SIL/IR/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ SILModule::~SILModule() {
}

void SILModule::checkForLeaks() const {

/// Leak checking is not thread safe, because the instruction counters are
/// global non-atomic variables. Leak checking can only be done in case there
/// is a single SILModule in a single thread.
if (!getOptions().checkSILModuleLeaks)
return;

int instsInModule = std::distance(scheduledForDeletion.begin(),
scheduledForDeletion.end());
for (const SILFunction &F : *this) {
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ ParseSILModuleRequest::evaluate(Evaluator &evaluator,
auto bufferID = SF->getBufferID();
assert(bufferID);

// For leak detection.
SILInstruction::resetInstructionCounts();

auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
desc.opts);
SILParserState parserState(*silMod.get());
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,9 @@ ASTLoweringRequest::evaluate(Evaluator &evaluator,
return llvm::cantFail(evaluator(ParseSILModuleRequest{desc}));
}

// For leak detection.
SILInstruction::resetInstructionCounts();

auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
desc.opts);

Expand Down
1 change: 1 addition & 0 deletions tools/sil-opt/SILOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ int main(int argc, char **argv) {
SILOpts.VerifySILOwnership = !DisableSILOwnershipVerifier;
SILOpts.OptRecordFile = RemarksFilename;
SILOpts.OptRecordPasses = RemarksPasses;
SILOpts.checkSILModuleLeaks = true;

SILOpts.VerifyExclusivity = VerifyExclusivity;
if (EnforceExclusivity.getNumOccurrences() != 0) {
Expand Down