[clang] [clang-tools-extra] [clang-tidy] Improve performance of misc-const-correctness (PR #72705)
https://github.com/HerrCai0907 approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/72705 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Improve performance of misc-const-correctness (PR #72705)
https://github.com/PiotrZSL updated https://github.com/llvm/llvm-project/pull/72705 >From 1f9b443a92446ae36825152535706037ef2e87b4 Mon Sep 17 00:00:00 2001 From: Piotr Zegar Date: Wed, 15 Nov 2023 16:52:00 + Subject: [PATCH 1/2] [clang-tidy] Improve performance of misc-const-correctness Replaced certain AST matchers in ExprMutationAnalyzer with a more direct utilization of AST classes. The primary bottleneck was identified in the canResolveToExpr AST matcher. Since this matcher was employed multiple times and used recursively, each invocation led to the constant creation and destruction of other matchers within it. Additionally, the continual comparison of DynTypedNode resulted in significant performance degradation. The optimization was tested on the TargetLowering.cpp file. Originally, the check took 156 seconds on that file, but after implementing this enhancement, it now takes approximately 40 seconds, making it nearly four times faster. Despite this improvement, there are still numerous issues in this file. To further reduce the computational cost of this class, it is advisable to consider removing the remaining matchers and exploring alternatives such as leveraging RecursiveASTVisitor and increasing the direct use of AST classes. --- clang-tools-extra/docs/ReleaseNotes.rst | 3 +- clang/lib/Analysis/ExprMutationAnalyzer.cpp | 350 +++- 2 files changed, 188 insertions(+), 165 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 4d25e2ebe85f5f..2960ef644fde4b 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -358,7 +358,8 @@ Changes in existing checks ` check to avoid false positive when using pointer to member function. Additionally, the check no longer emits a diagnostic when a variable that is not type-dependent is an operand of a - type-dependent binary operator. + type-dependent binary operator. Improved performance of the check through + optimizations. - Improved :doc:`misc-include-cleaner ` check by adding option diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 624a643cc60e4b..760c867ef79f74 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -15,6 +15,76 @@ namespace clang { using namespace ast_matchers; +static bool canResolveToExprImpl(const Expr *Node, const Expr *Target) { + + const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) { +if (Matcher(E)) + return true; +if (const auto *Cast = dyn_cast(E)) { + if ((Cast->getCastKind() == CK_DerivedToBase || + Cast->getCastKind() == CK_UncheckedDerivedToBase) && + Matcher(Cast->getSubExpr())) +return true; +} +return false; + }; + + const auto EvalCommaExpr = [](const Expr *E, auto Matcher) { +const Expr *Result = E; +while (const auto *BOComma = + dyn_cast_or_null(Result->IgnoreParens())) { + if (!BOComma->isCommaOp()) +break; + Result = BOComma->getRHS(); +} + +return Result != E && Matcher(Result); + }; + + // The 'ConditionalOperatorM' matches on ` ? : `. + // This matching must be recursive because `` can be anything resolving + // to the `InnerMatcher`, for example another conditional operator. + // The edge-case `BaseClass = ? DerivedVar1 : DerivedVar2;` + // is handled, too. The implicit cast happens outside of the conditional. + // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))` + // below. + const auto ConditionalOperatorM = [Target](const Expr *E, auto Matcher) { +if (const auto *OP = dyn_cast(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) +if (canResolveToExprImpl(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) +if (canResolveToExprImpl(FE, Target)) + return true; +} +return false; + }; + + const auto ElvisOperator = [Target](const Expr *E, auto Matcher) { +if (const auto *OP = dyn_cast(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) +if (canResolveToExprImpl(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) +if (canResolveToExprImpl(FE, Target)) + return true; +} +return false; + }; + + const auto *EP = Node->IgnoreParens(); + return IgnoreDerivedToBase(EP, + [&](const Expr *E) { + return E == Target || + ConditionalOperatorM(E, Target) || + ElvisOperator(E, Target); + }) || + EvalCommaExpr(EP, [&](const Expr *E) { + return IgnoreDerivedToBase( + E->IgnoreParens(), [&](const Expr *EE) {
[clang] [clang-tools-extra] [clang-tidy] Improve performance of misc-const-correctness (PR #72705)
@@ -15,6 +15,76 @@ namespace clang { using namespace ast_matchers; +static bool canResolveToExprImpl(const Expr *Node, const Expr *Target) { HerrCai0907 wrote: This function is hard to understand because it used matcher style naming but logic operator style code. https://github.com/llvm/llvm-project/pull/72705 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Improve performance of misc-const-correctness (PR #72705)
@@ -15,6 +15,76 @@ namespace clang { using namespace ast_matchers; +static bool canResolveToExprImpl(const Expr *Node, const Expr *Target) { + + const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) { +if (Matcher(E)) + return true; +if (const auto *Cast = dyn_cast(E)) { + if ((Cast->getCastKind() == CK_DerivedToBase || + Cast->getCastKind() == CK_UncheckedDerivedToBase) && + Matcher(Cast->getSubExpr())) +return true; +} +return false; + }; + + const auto EvalCommaExpr = [](const Expr *E, auto Matcher) { +const Expr *Result = E; +while (const auto *BOComma = + dyn_cast_or_null(Result->IgnoreParens())) { + if (!BOComma->isCommaOp()) +break; + Result = BOComma->getRHS(); +} + +return Result != E && Matcher(Result); + }; + + // The 'ConditionalOperatorM' matches on ` ? : `. + // This matching must be recursive because `` can be anything resolving + // to the `InnerMatcher`, for example another conditional operator. + // The edge-case `BaseClass = ? DerivedVar1 : DerivedVar2;` + // is handled, too. The implicit cast happens outside of the conditional. + // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))` + // below. + const auto ConditionalOperatorM = [Target](const Expr *E, auto Matcher) { HerrCai0907 wrote: useless arguments `Matcher` https://github.com/llvm/llvm-project/pull/72705 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Improve performance of misc-const-correctness (PR #72705)
llvmbot wrote: @llvm/pr-subscribers-clang-static-analyzer-1 @llvm/pr-subscribers-clang-tidy Author: Piotr Zegar (PiotrZSL) Changes Replaced certain AST matchers in ExprMutationAnalyzer with a more direct utilization of AST classes. The primary bottleneck was identified in the canResolveToExpr AST matcher. Since this matcher was employed multiple times and used recursively, each invocation led to the constant creation and destruction of other matchers within it. Additionally, the continual comparison of DynTypedNode resulted in significant performance degradation. The optimization was tested on the TargetLowering.cpp file. Originally, the check took 156 seconds on that file, but after implementing this enhancement, it now takes approximately 40 seconds, making it nearly four times faster. Despite this improvement, there are still numerous issues in this file. To further reduce the computational cost of this class, it is advisable to consider removing the remaining matchers and exploring alternatives such as leveraging RecursiveASTVisitor and increasing the direct use of AST classes. Closes #71786 --- Patch is 26.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72705.diff 2 Files Affected: - (modified) clang-tools-extra/docs/ReleaseNotes.rst (+2-1) - (modified) clang/lib/Analysis/ExprMutationAnalyzer.cpp (+186-164) ``diff diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 23111be4371e2e1..eae460e7936ffd7 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -326,7 +326,8 @@ Changes in existing checks ` check to avoid false positive when using pointer to member function. Additionally, the check no longer emits a diagnostic when a variable that is not type-dependent is an operand of a - type-dependent binary operator. + type-dependent binary operator. Improved performance of the check through + optimizations. - Improved :doc:`misc-include-cleaner ` check by adding option diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 624a643cc60e4ba..760c867ef79f74d 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -15,6 +15,76 @@ namespace clang { using namespace ast_matchers; +static bool canResolveToExprImpl(const Expr *Node, const Expr *Target) { + + const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) { +if (Matcher(E)) + return true; +if (const auto *Cast = dyn_cast(E)) { + if ((Cast->getCastKind() == CK_DerivedToBase || + Cast->getCastKind() == CK_UncheckedDerivedToBase) && + Matcher(Cast->getSubExpr())) +return true; +} +return false; + }; + + const auto EvalCommaExpr = [](const Expr *E, auto Matcher) { +const Expr *Result = E; +while (const auto *BOComma = + dyn_cast_or_null(Result->IgnoreParens())) { + if (!BOComma->isCommaOp()) +break; + Result = BOComma->getRHS(); +} + +return Result != E && Matcher(Result); + }; + + // The 'ConditionalOperatorM' matches on ` ? : `. + // This matching must be recursive because `` can be anything resolving + // to the `InnerMatcher`, for example another conditional operator. + // The edge-case `BaseClass = ? DerivedVar1 : DerivedVar2;` + // is handled, too. The implicit cast happens outside of the conditional. + // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))` + // below. + const auto ConditionalOperatorM = [Target](const Expr *E, auto Matcher) { +if (const auto *OP = dyn_cast(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) +if (canResolveToExprImpl(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) +if (canResolveToExprImpl(FE, Target)) + return true; +} +return false; + }; + + const auto ElvisOperator = [Target](const Expr *E, auto Matcher) { +if (const auto *OP = dyn_cast(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) +if (canResolveToExprImpl(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) +if (canResolveToExprImpl(FE, Target)) + return true; +} +return false; + }; + + const auto *EP = Node->IgnoreParens(); + return IgnoreDerivedToBase(EP, + [&](const Expr *E) { + return E == Target || + ConditionalOperatorM(E, Target) || + ElvisOperator(E, Target); + }) || + EvalCommaExpr(EP, [&](const Expr *E) { + return IgnoreDerivedToBase( + E->IgnoreParens(), [&](const Expr *EE) { return EE == Target;