https://github.com/grigorypas created https://github.com/llvm/llvm-project/pull/165777
Introduces the `flatten_deep` attribute as an extension to the existing `flatten` attribute. While `flatten` only inlines immediate callsites, `flatten_deep` enables inlining of function calls and their transitive callees up to a specified depth, effectively providing full flattening of the call tree. The attribute takes a single unsigned integer argument representing the maximum call tree depth to inline. For example, flatten_deep(3) will inline all calls within a function, then inline all calls within those inlined functions (depth 2), and then inline all calls within those functions (depth 3). This is part 1 of 3. Future PRs will: - Add a corresponding LLVM IR attribute - Implement inlining logic in the AlwaysInliner pass >From f84132355882ef7d909e2970f6dc251efd4785f4 Mon Sep 17 00:00:00 2001 From: Grigory Pastukhov <[email protected]> Date: Fri, 24 Oct 2025 12:58:33 -0700 Subject: [PATCH] Add flatten_deep attribute to clang --- clang/include/clang/Basic/Attr.td | 7 ++++++ clang/include/clang/Basic/AttrDocs.td | 23 +++++++++++++++++++ clang/lib/Sema/SemaDeclAttr.cpp | 21 +++++++++++++++++ ...a-attribute-supported-attributes-list.test | 1 + clang/test/Sema/attr-flatten-deep.c | 14 +++++++++++ 5 files changed, 66 insertions(+) create mode 100644 clang/test/Sema/attr-flatten-deep.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 749f531ec9ab1..1ccd659e49e63 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1984,6 +1984,13 @@ def Flatten : InheritableAttr { let SimpleHandler = 1; } +def FlattenDeep : InheritableAttr { + let Spellings = [Clang<"flatten_deep">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Args = [UnsignedArgument<"MaxDepth">]; + let Documentation = [FlattenDeepDocs]; +} + def Format : InheritableAttr { let Spellings = [GCC<"format">]; let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">, diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 2fdd041c1b46e..f4280531019f5 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4032,6 +4032,29 @@ callee is unavailable or if the callee has the ``noinline`` attribute. }]; } +def FlattenDeepDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``flatten_deep`` attribute causes calls within the attributed function and +their transitive callees to be inlined up to a specified depth, unless it is +impossible to do so (for example if the body of the callee is unavailable or if +the callee has the ``noinline`` attribute). + +This attribute takes a single unsigned integer argument representing the maximum +depth of the call tree to inline. For example, ``__attribute__((flatten_deep(3)))`` +will inline all calls within the function, then inline all calls within those +inlined functions (depth 2), and then inline all calls within those functions +(depth 3). + +.. code-block:: c++ + + __attribute__((flatten_deep(3))) + void process_data() { + // All calls up to 3 levels deep in the call tree will be inlined + } + }]; +} + def FormatDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 964a2a791e18f..1a78dfce6e1f3 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3695,6 +3695,24 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum)); } +static void handleFlattenDeepAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); + uint32_t maxDepth; + if (!S.checkUInt32Argument(AL, E, maxDepth)) { + AL.setInvalid(); + return; + } + + if (maxDepth == 0) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL << E->getSourceRange(); + AL.setInvalid(); + return; + } + + D->addAttr(::new (S.Context) FlattenDeepAttr(S.Context, AL, maxDepth)); +} + ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, StringRef NewUserDiagnostic) { if (const auto *EA = D->getAttr<ErrorAttr>()) { @@ -7236,6 +7254,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Format: handleFormatAttr(S, D, AL); break; + case ParsedAttr::AT_FlattenDeep: + handleFlattenDeepAttr(S, D, AL); + break; case ParsedAttr::AT_FormatMatches: handleFormatMatchesAttr(S, D, AL); break; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index ab4153a64f028..da6152dbff3a5 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -86,6 +86,7 @@ // CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: FlagEnum (SubjectMatchRule_enum) // CHECK-NEXT: Flatten (SubjectMatchRule_function) +// CHECK-NEXT: FlattenDeep (SubjectMatchRule_function) // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) diff --git a/clang/test/Sema/attr-flatten-deep.c b/clang/test/Sema/attr-flatten-deep.c new file mode 100644 index 0000000000000..92bc792424332 --- /dev/null +++ b/clang/test/Sema/attr-flatten-deep.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// Test basic usage - valid +__attribute__((flatten_deep(3))) +void test_valid() { +} + +// Test attribute on non-function - should error +__attribute__((flatten_deep(3))) int x; // expected-error {{'flatten_deep' attribute only applies to functions}} + +// Test depth = 0 - should error (depth must be >= 1) +__attribute__((flatten_deep(0))) // expected-error {{'flatten_deep' attribute must be greater than 0}} +void test_depth_zero() { +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
