Skip to content

Commit

Permalink
[Clang] Improve compile times when forming a DeclRef outside of a cap…
Browse files Browse the repository at this point in the history
…turing scope.

The logic of whether an entity needs to be captured has become
quite complex and the recent changes in https://reviews.llvm.org/D124351
ad a mesurable negative impact on compile times.

However, in the absence of capturing scopes (lambda, block, region)
we usually can avoid running most of that logic
(except that we do need to diagnostic when a nested function
refers to a local variable in the scope of the outer function.).

This patch track whether there is currently an active capturing
scope and exit `tryCaptureVariable` early when there isn't.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D150038
  • Loading branch information
cor3ntin committed May 8, 2023
1 parent 616f830 commit a7579b2
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 1 deletion.
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -806,6 +806,9 @@ class Sema final {
/// context.
unsigned FunctionScopesStart = 0;

/// Track the number of currently active capturing scopes.
unsigned CapturingFunctionScopes = 0;

ArrayRef<sema::FunctionScopeInfo*> getFunctionScopes() const {
return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart,
FunctionScopes.end());
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/Sema.cpp
Expand Up @@ -2138,11 +2138,13 @@ void Sema::PushFunctionScope() {
void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(),
BlockScope, Block));
CapturingFunctionScopes++;
}

LambdaScopeInfo *Sema::PushLambdaScope() {
LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics());
FunctionScopes.push_back(LSI);
CapturingFunctionScopes++;
return LSI;
}

Expand Down Expand Up @@ -2264,6 +2266,8 @@ Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,

void Sema::PoppedFunctionScopeDeleter::
operator()(sema::FunctionScopeInfo *Scope) const {
if (!Scope->isPlainFunction())
Self->CapturingFunctionScopes--;
// Stash the function scope for later reuse if it's for a normal function.
if (Scope->isPlainFunction() && !Self->CachedFunctionScope)
Self->CachedFunctionScope.reset(Scope);
Expand Down Expand Up @@ -2694,6 +2698,7 @@ void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
OpenMPCaptureLevel);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
CapturingFunctionScopes++;
}

CapturedRegionScopeInfo *Sema::getCurCapturedRegion() {
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Expand Up @@ -19221,6 +19221,15 @@ bool Sema::tryCaptureVariable(
// An init-capture is notionally from the context surrounding its
// declaration, but its parent DC is the lambda class.
DeclContext *VarDC = Var->getDeclContext();
DeclContext *DC = CurContext;

// tryCaptureVariable is called every time a DeclRef is formed,
// it can therefore have non-negigible impact on performances.
// For local variables and when there is no capturing scope,
// we can bailout early.
if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC))
return true;

const auto *VD = dyn_cast<VarDecl>(Var);
if (VD) {
if (VD->isInitCapture())
Expand All @@ -19230,7 +19239,6 @@ bool Sema::tryCaptureVariable(
}
assert(VD && "Cannot capture a null variable");

DeclContext *DC = CurContext;
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
// We need to sync up the Declaration Context with the
Expand Down

0 comments on commit a7579b2

Please sign in to comment.