[clang] [clang] Optimize RecursiveASTVisitor instantiations for size (PR #202657)

David Zbarsky via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 9 07:01:47 PDT 2026


https://github.com/dzbarsky created https://github.com/llvm/llvm-project/pull/202657

RecursiveASTVisitor is a CRTP template instantiated by hundreds of Clang tools and checks. The optimizer currently duplicates large traversal functions in each instantiation.

Apply Clang minsize to every RecursiveASTVisitor member function. minsize enables size-oriented inlining and outlining for the generated traversal functions without changing RecursiveASTVisitor dispatch or traversal order.

In the stripped all-tools multicall binary, this reduces size from 152,475,496 bytes to 150,635,672 bytes, saving 1,839,824 bytes (1.207%).

Correctness validation:

- bazel build @llvm-project//llvm --config=prebuilt --config=remote

- clang-tidy --checks=* produced byte-identical 13,886-line output before and after the change on a 1,500-line generated C file.

Performance validation:

- The LLVM repository has no RecursiveASTVisitor benchmark target.

- hyperfine --warmup 3 --runs 15 measured clang-tidy --checks=* on the same file.

- Baseline user time: 435.5 ms; patched user time: 428.9 ms. The result shows no performance regression.

Work towards #202616

>From 974d022278c3916099166a77c1cb5242f91b733d Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Mon, 8 Jun 2026 13:03:10 -0400
Subject: [PATCH] [clang] Optimize RecursiveASTVisitor instantiations for size

RecursiveASTVisitor is a CRTP template instantiated by hundreds of Clang tools and checks. The optimizer currently duplicates large traversal functions in each instantiation.

Apply Clang minsize to every RecursiveASTVisitor member function. minsize enables size-oriented inlining and outlining for the generated traversal functions without changing RecursiveASTVisitor dispatch or traversal order.

In the stripped all-tools multicall binary, this reduces size from 152,475,496 bytes to 150,635,672 bytes, saving 1,839,824 bytes (1.207%).

Correctness validation:

- bazel build @llvm-project//llvm --config=prebuilt --config=remote

- clang-tidy --checks=* produced byte-identical 13,886-line output before and after the change on a 1,500-line generated C file.

Performance validation:

- The LLVM repository has no RecursiveASTVisitor benchmark target.

- hyperfine --warmup 3 --runs 15 measured clang-tidy --checks=* on the same file.

- Baseline user time: 435.5 ms; patched user time: 428.9 ms. The result shows no performance regression.
---
 clang/include/clang/AST/RecursiveASTVisitor.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 3b9bafffe1bc1..88e56464c79a9 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -153,6 +153,10 @@ isSameMethod([[maybe_unused]] FirstMethodPtrTy FirstMethodPtr,
 /// By default, this visitor preorder traverses the AST. If postorder traversal
 /// is needed, the \c shouldTraversePostOrder method needs to be overridden
 /// to return \c true.
+#ifdef __clang__
+#pragma clang attribute push(__attribute__((minsize)), apply_to = function)
+#endif
+
 template <typename Derived> class RecursiveASTVisitor {
 public:
   /// A queue used for performing data recursion over statements.
@@ -4350,6 +4354,10 @@ DEF_TRAVERSE_STMT(HLSLOutArgExpr, {})
 #undef TRAVERSE_STMT
 #undef TRAVERSE_STMT_BASE
 
+#ifdef __clang__
+#pragma clang attribute pop
+#endif
+
 #undef TRY_TO
 
 } // end namespace clang



More information about the cfe-commits mailing list