llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Mehdi Amini (joker-eph) <details> <summary>Changes</summary> Keep common expression evaluation records compact by moving diagnostic and feature-specific collections behind one lazily allocated rare-data object. Add a no-rare-data pop path to avoid checking empty collections. CTMark O0 (3 samples): 29.439800 s -> 29.219367 s (-0.749%). Impact on significant TUs in MLIR build time: - `mlir/lib/RegisterAllDialects.cpp`: 1.6043% fewer retired instructions. - `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 0.9162% fewer retired instructions. Assisted-by: Codex --- Patch is 28.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/223036.diff 9 Files Affected: - (modified) clang/include/clang/Sema/Sema.h (+47-31) - (modified) clang/lib/Parse/ParseStmt.cpp (+5-4) - (modified) clang/lib/Sema/SemaChecking.cpp (+12-6) - (modified) clang/lib/Sema/SemaExpr.cpp (+83-44) - (modified) clang/lib/Sema/SemaExprCXX.cpp (+10-8) - (modified) clang/lib/Sema/SemaExprMember.cpp (+1-1) - (modified) clang/lib/Sema/SemaInit.cpp (+3-1) - (modified) clang/lib/Sema/SemaLambda.cpp (+1-1) - (modified) clang/lib/Sema/TreeTransform.h (+10-6) ``````````diff diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4ff4c669a6b70..a74d1b58a4a8a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6809,12 +6809,6 @@ class Sema final : public SemaBase { /// this expression evaluation context. unsigned NumCleanupObjects; - MaybeODRUseExprSet SavedMaybeODRUseExprs; - - /// The lambdas that are present within this context, if it - /// is indeed an unevaluated context. - SmallVector<LambdaExpr *, 2> Lambdas; - /// The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. @@ -6825,38 +6819,60 @@ class Sema final : public SemaBase { /// diagnostic to reference the declaration as a whole. VarDecl *DeclForInitializer = nullptr; - /// If we are processing a decltype type, a set of call expressions - /// for which we have deferred checking the completeness of the return type. - SmallVector<CallExpr *, 8> DelayedDecltypeCalls; + /// Collections used by uncommon evaluation-context features. Keeping them + /// out of line avoids constructing empty containers for ordinary contexts. + struct RareData { + MaybeODRUseExprSet SavedMaybeODRUseExprs; + + /// The lambdas that are present within an unevaluated context. + SmallVector<LambdaExpr *, 2> Lambdas; + + /// If we are processing a decltype type, call expressions for which we + /// have deferred checking the completeness of the return type. + SmallVector<CallExpr *, 8> DelayedDecltypeCalls; + + /// If we are processing a decltype type, temporary binding expressions + /// for which we have deferred checking the destructor. + SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds; - /// If we are processing a decltype type, a set of temporary binding - /// expressions for which we have deferred checking the destructor. - SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds; + llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs; - llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs; + /// Expressions appearing as the LHS of a volatile assignment in this + /// context. We warn when popping the context unless they are discarded- + /// value expressions or unevaluated operands. + SmallVector<Expr *, 2> VolatileAssignmentLHSs; - /// Expressions appearing as the LHS of a volatile assignment in this - /// context. We produce a warning for these when popping the context if - /// they are not discarded-value expressions nor unevaluated operands. - SmallVector<Expr *, 2> VolatileAssignmentLHSs; + /// Set of candidates for starting an immediate invocation. + llvm::SmallVector<ImmediateInvocationCandidate, 4> + ImmediateInvocationCandidates; - /// Set of candidates for starting an immediate invocation. - llvm::SmallVector<ImmediateInvocationCandidate, 4> - ImmediateInvocationCandidates; + /// DeclRefExprs referencing a consteval function in a context not already + /// known to be immediately invoked. + llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval; - /// Set of DeclRefExprs referencing a consteval function when used in a - /// context not already known to be immediately invoked. - llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval; + /// P2718R0 - Lifetime extension in range-based for loops. + /// Materialized temporaries in for-range-init expressions whose lifetime + /// needs extending. Collected when InLifetimeExtendingContext is true. + SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps; - /// P2718R0 - Lifetime extension in range-based for loops. - /// MaterializeTemporaryExprs in for-range-init expressions which need to - /// extend lifetime. Add MaterializeTemporaryExpr* if the value of - /// InLifetimeExtendingContext is true. - SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps; + /// Gathered accesses to potentially misaligned members due to the packed + /// attribute. + SmallVector<MisalignedMember, 4> MisalignedMembers; + }; + + /// Null means that every rare-data collection is empty. + std::unique_ptr<RareData> Rare; + + /// Obtain storage for adding rare state, allocating it on first use. + RareData &getOrCreateRareData() { + if (!Rare) + Rare = std::make_unique<RareData>(); + return *Rare; + } - /// Small set of gathered accesses to potentially misaligned members - /// due to the packed attribute. - SmallVector<MisalignedMember, 4> MisalignedMembers; + /// Inspect rare state without allocating storage for an empty context. + RareData *getRareData() { return Rare.get(); } + const RareData *getRareData() const { return Rare.get(); } /// \brief Describes whether we are in an expression constext which we have /// to handle differently. diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 5e67cd551bff8..029b6c3f7ead6 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1965,13 +1965,14 @@ void Parser::ParseForRangeInitializerAfterColon(ForRangeInit &FRI, } // Before c++23, ForRangeLifetimeExtendTemps should be empty. - assert(getLangOpts().CPlusPlus23 || - Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty()); + auto *Rare = Actions.ExprEvalContexts.back().getRareData(); + assert(getLangOpts().CPlusPlus23 || !Rare || + Rare->ForRangeLifetimeExtendTemps.empty()); // Move the collected materialized temporaries into ForRangeInit before // ForRangeInitContext exit. - FRI.LifetimeExtendTemps = - std::move(Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps); + if (Rare) + FRI.LifetimeExtendTemps = std::move(Rare->ForRangeLifetimeExtendTemps); } StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 25996ddbc0558..86e1062c8cc8f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -16950,12 +16950,16 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment) { - currentEvaluationContext().MisalignedMembers.emplace_back(E, RD, MD, - Alignment); + currentEvaluationContext() + .getOrCreateRareData() + .MisalignedMembers.emplace_back(E, RD, MD, Alignment); } void Sema::DiagnoseMisalignedMembers() { - for (MisalignedMember &m : currentEvaluationContext().MisalignedMembers) { + auto *Rare = currentEvaluationContext().getRareData(); + if (!Rare) + return; + for (MisalignedMember &m : Rare->MisalignedMembers) { const NamedDecl *ND = m.RD; if (ND->getName().empty()) { if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl()) @@ -16964,7 +16968,7 @@ void Sema::DiagnoseMisalignedMembers() { Diag(m.E->getBeginLoc(), diag::warn_taking_address_of_packed_member) << m.MD << ND << m.E->getSourceRange(); } - currentEvaluationContext().MisalignedMembers.clear(); + Rare->MisalignedMembers.clear(); } void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { @@ -16975,8 +16979,10 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); if (isa<MemberExpr>(Op)) { - auto &MisalignedMembersForExpr = - currentEvaluationContext().MisalignedMembers; + auto *Rare = currentEvaluationContext().getRareData(); + if (!Rare) + return; + auto &MisalignedMembersForExpr = Rare->MisalignedMembers; auto *MA = llvm::find(MisalignedMembersForExpr, MisalignedMember(Op)); if (MA != MisalignedMembersForExpr.end() && (T->isDependentType() || T->isIntegerType() || diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9fa8e517d9098..86e7f0dcf47ba 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5382,7 +5382,8 @@ void Sema::CheckAddressOfNoDeref(const Expr *E) { while ((Member = dyn_cast<MemberExpr>(StrippedExpr)) && !Member->isArrow()) StrippedExpr = Member->getBase()->IgnoreParenImpCasts(); - LastRecord.PossibleDerefs.erase(StrippedExpr); + if (auto *Rare = LastRecord.getRareData()) + Rare->PossibleDerefs.erase(StrippedExpr); } void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) { @@ -5397,7 +5398,7 @@ void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) { return; if (ResultTy->hasAttr(attr::NoDeref)) { - LastRecord.PossibleDerefs.insert(E); + LastRecord.getOrCreateRareData().PossibleDerefs.insert(E); return; } @@ -5416,7 +5417,7 @@ void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) { if (const auto *Ptr = dyn_cast<PointerType>(Base->getType())) { if (Ptr->getPointeeType()->hasAttr(attr::NoDeref)) - LastRecord.PossibleDerefs.insert(E); + LastRecord.getOrCreateRareData().PossibleDerefs.insert(E); } } @@ -6799,7 +6800,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // an invalid immediate call. if (auto *DRE = dyn_cast<DeclRefExpr>(Fn->IgnoreParens()); DRE && Call.get()->isValueDependent()) { - currentEvaluationContext().ReferenceToConsteval.erase(DRE); + if (auto *Rare = currentEvaluationContext().getRareData()) + Rare->ReferenceToConsteval.erase(DRE); } } return Call; @@ -14730,7 +14732,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, // A simple-assignment whose left operand is of a volatile-qualified // type is deprecated unless the assignment is either a discarded-value // expression or an unevaluated operand - ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); + ExprEvalContexts.back() + .getOrCreateRareData() + .VolatileAssignmentLHSs.push_back(LHSExpr); } } @@ -16584,7 +16588,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) && !isa<ArrayType>(UO->getType().getDesugaredType(Context)) && !isUnevaluatedContext()) - ExprEvalContexts.back().PossibleDerefs.insert(UO); + ExprEvalContexts.back().getOrCreateRareData().PossibleDerefs.insert(UO); // Convert the result back to a half vector. if (ConvertHalfVec) @@ -18322,29 +18326,35 @@ void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { + const auto &Prev = currentEvaluationContext(); + bool InDiscardedStatement = Prev.isDiscardedStatementContext(); + bool InImmediateFunctionContext = + Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated(); + bool InImmediateEscalatingFunctionContext = + Prev.InImmediateEscalatingFunctionContext; + ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, LambdaContextDecl, ExprContext); + auto &Current = currentEvaluationContext(); // Discarded statements and immediate contexts nested in other // discarded statements or immediate context are themselves // a discarded statement or an immediate context, respectively. - ExprEvalContexts.back().InDiscardedStatement = - parentEvaluationContext().isDiscardedStatementContext(); + Current.InDiscardedStatement = InDiscardedStatement; // C++23 [expr.const]/p15 // An expression or conversion is in an immediate function context if [...] // it is a subexpression of a manifestly constant-evaluated expression or // conversion. - const auto &Prev = parentEvaluationContext(); - ExprEvalContexts.back().InImmediateFunctionContext = - Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated(); + Current.InImmediateFunctionContext = InImmediateFunctionContext; - ExprEvalContexts.back().InImmediateEscalatingFunctionContext = - Prev.InImmediateEscalatingFunctionContext; + Current.InImmediateEscalatingFunctionContext = + InImmediateEscalatingFunctionContext; Cleanup.reset(); if (!MaybeODRUseExprs.empty()) - std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); + std::swap(MaybeODRUseExprs, + Current.getOrCreateRareData().SavedMaybeODRUseExprs); } void @@ -18434,7 +18444,10 @@ const DeclRefExpr *CheckPossibleDeref(Sema &S, const Expr *PossibleDeref) { } // namespace void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { - for (const Expr *E : Rec.PossibleDerefs) { + auto *Rare = Rec.getRareData(); + if (!Rare) + return; + for (const Expr *E : Rare->PossibleDerefs) { const DeclRefExpr *DeclRef = CheckPossibleDeref(*this, E); if (DeclRef) { const ValueDecl *Decl = DeclRef->getDecl(); @@ -18446,7 +18459,7 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { << E->getSourceRange(); } } - Rec.PossibleDerefs.clear(); + Rare->PossibleDerefs.clear(); } void Sema::CheckUnusedVolatileAssignment(Expr *E) { @@ -18458,8 +18471,8 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { // drives a deprecation warning so doesn't affect conformance. if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) { if (BO->getOpcode() == BO_Assign) { - auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; - llvm::erase(LHSs, BO->getLHS()); + if (auto *Rare = ExprEvalContexts.back().getRareData()) + llvm::erase(Rare->VolatileAssignmentLHSs, BO->getLHS()); } } } @@ -18499,7 +18512,8 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) if (auto *DeclRef = dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) - ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); + if (auto *Rare = ExprEvalContexts.back().getRareData()) + Rare->ReferenceToConsteval.erase(DeclRef); // C++23 [expr.const]/p16 // An expression or conversion is immediate-escalating if it is not initially @@ -18555,7 +18569,9 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { /// Value-dependent constant expressions should not be immediately /// evaluated until they are instantiated. if (!Res->isValueDependent()) - ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); + ExprEvalContexts.back() + .getOrCreateRareData() + .ImmediateInvocationCandidates.emplace_back(Res, 0); return Res; } @@ -18691,8 +18707,8 @@ static void RemoveNestedImmediateInvocation( return Res; } bool AllowSkippingFirstCXXConstructExpr = true; - } Transformer(SemaRef, Rec.ReferenceToConsteval, - Rec.ImmediateInvocationCandidates, It); + } Transformer(SemaRef, Rec.getRareData()->ReferenceToConsteval, + Rec.getRareData()->ImmediateInvocationCandidates, It); /// CXXConstructExpr with a single argument are getting skipped by /// TreeTransform in some situtation because they could be implicit. This @@ -18716,8 +18732,10 @@ static void RemoveNestedImmediateInvocation( static void HandleImmediateInvocations(Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec) { - if ((Rec.ImmediateInvocationCandidates.size() == 0 && - Rec.ReferenceToConsteval.size() == 0) || + auto *Rare = Rec.getRareData(); + if (!Rare || + (Rare->ImmediateInvocationCandidates.empty() && + Rare->ReferenceToConsteval.empty()) || Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation) return; @@ -18745,7 +18763,7 @@ HandleImmediateInvocations(Sema &SemaRef, /// ImmediateInvocationCandidates in order to avoid duplicate diagnostics. /// Otherwise we only need to remove ReferenceToConsteval in the immediate /// invocation. - if (Rec.ImmediateInvocationCandidates.size() > 1 || + if (Rare->ImmediateInvocationCandidates.size() > 1 || !SemaRef.FailedImmediateInvocations.empty()) { /// Prevent sema calls during the tree transform from adding pointers that @@ -18756,12 +18774,12 @@ HandleImmediateInvocations(Sema &SemaRef, /// Prevent diagnostic during tree transfrom as they are duplicates Sema::TentativeAnalysisScope DisableDiag(SemaRef); - for (auto It = Rec.ImmediateInvocationCandidates.rbegin(); - It != Rec.ImmediateInvocationCandidates.rend(); It++) + for (auto It = Rare->ImmediateInvocationCandidates.rbegin(); + It != Rare->ImmediateInvocationCandidates.rend(); It++) if (!It->getInt()) RemoveNestedImmediateInvocation(SemaRef, Rec, It); - } else if (Rec.ImmediateInvocationCandidates.size() == 1 && - Rec.ReferenceToConsteval.size()) { + } else if (Rare->ImmediateInvocationCandidates.size() == 1 && + !Rare->ReferenceToConsteval.empty()) { struct SimpleRemove : DynamicRecursiveASTVisitor { llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet; SimpleRemove(llvm::SmallPtrSetImpl<DeclRefExpr *> &S) : DRSet(S) {} @@ -18769,14 +18787,14 @@ HandleImmediateInvocations(Sema &SemaRef, DRSet.erase(E); return DRSet.size(); } - } Visitor(Rec.ReferenceToConsteval); + } Visitor(Rare->ReferenceToConsteval); Visitor.TraverseStmt( - Rec.ImmediateInvocationCandidates.front().getPointer()->getSubExpr()); + Rare->ImmediateInvocationCandidates.front().getPointer()->getSubExpr()); } - for (auto CE : Rec.ImmediateInvocationCandidates) + for (auto CE : Rare->ImmediateInvocationCandidates) if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); - for (auto *DR : Rec.ReferenceToConsteval) { + for (auto *DR : Rare->ReferenceToConsteval) { // If the expression is immediate escalating, it is not an error; // The outer context itself becomes immediate and further errors, // if any, will be handled by DiagnoseImmediateEscalatingReason. @@ -18825,7 +18843,23 @@ HandleImmediateInvocations(Sema &SemaRef, void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); - if (!Rec.Lambdas.empty()) { + auto *Rare = Rec.getRareData(); + if (!Rare) { + if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { + ExprCleanupObjects.erase(ExprCleanupObjects.begin() + + Rec.NumCleanupObjects, + ExprCleanupObjects.end()); + Cleanup = Rec.ParentCleanup; + CleanupVarDeclMarking(); + MaybeODRUseExprs.clear(); + } else { + Cleanup.mergeFrom(Rec.ParentCleanup); + } + ExprEvalContexts.pop_back(); + return; + } + + if (!Rare->Lambdas.empty()) { using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind; if (!getLangOpts().CPlusPlus20 && (Rec.ExprContext == ExpressionKind::EK_TemplateArgument || @@ -18850,7 +18884,7 @@ void Sema::PopExpressionEvaluationContext() { } else llvm_unreachable("Couldn't infer lambda error message."); - for (const auto *L : Rec.Lambdas) + for (const auto *L : Rare->Lambdas) Diag(L->getBeginLoc(), D); } } @@ -18859,9 +18893,10 @@ void Sema::PopExpressionEvaluationContext() { // exit if the previous also is a lifetime extending context. if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext && parentEvaluationContext().InLifetimeExtendingContext && - !Rec.ForRangeLifetimeExtendTemps.empty()) { - parentEvaluationContext().ForRangeLifetimeExtendTemps.append( - Rec.ForRangeLifetimeExtendTemps); + !Rare->ForRangeLifetimeExtendTemps.empty()) { + parentEvaluationContext() + ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/223036 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
