[clang] Revert "[Clang] Emit LLVM flatten attribute instead of per-callsite alwaysinline (#188615)" (PR #195314)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 1 11:14:47 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Grigory Pastukhov (grigorypas)
<details>
<summary>Changes</summary>
Reverts #<!-- -->188615 due to #<!-- -->195236 — Linux kernel build with LTO hangs.
---
Full diff: https://github.com/llvm/llvm-project/pull/195314.diff
5 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (-10)
- (modified) clang/lib/CodeGen/CGCall.cpp (+11)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (-3)
- (modified) clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c (+34-81)
- (modified) clang/test/CodeGen/flatten.c (+10-18)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c408196c3816b..6b66a4fa1a261 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -311,16 +311,6 @@ Attribute Changes in Clang
foreign language personality with a given function. Note that this does not
perform any ABI validation for the personality routine.
-- The ``__attribute__((flatten))`` attribute behavior has changed to match
- GCC. Previously, Clang only inlined direct callees of the attributed
- function. Now, all calls are inlined transitively, including calls
- introduced by inlining. Calls that cannot be inlined are left as-is:
- this includes callees marked ``noinline``, callees with incompatible ABI
- attributes (e.g. SME), callees without a visible definition, and
- recursive calls where a function already appears in the inlining chain.
- Flatten also works across ThinLTO module boundaries when callee
- definitions are available.
-
- The :doc:`ThreadSafetyAnalysis` attributes ``guarded_by`` and
``pt_guarded_by`` now accept multiple capability arguments with refined
access semantics: *writing* requires all listed capabilities to be held
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 3f1ece5fe5347..c584f2eeef937 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5992,6 +5992,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.
+ // Apply always_inline to all calls within flatten functions.
+ // FIXME: should this really take priority over __try, below?
+ if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
+ !InNoInlineAttributedStmt &&
+ !(TargetDecl && TargetDecl->hasAttr<NoInlineAttr>()) &&
+ !CGM.getTargetCodeGenInfo().wouldInliningViolateFunctionCallABI(
+ CallerDecl, CalleeDecl)) {
+ Attrs =
+ Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline);
+ }
+
// Disable inlining inside SEH __try blocks.
if (isSEHTryScope()) {
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index a96b767fd0d60..20a28c39af88a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2975,9 +2975,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (CodeGenOpts.DisableOutlining || D->hasAttr<NoOutlineAttr>())
B.addAttribute(llvm::Attribute::NoOutline);
- if (D->hasAttr<FlattenAttr>())
- B.addAttribute(llvm::Attribute::Flatten);
-
F->addFnAttrs(B);
llvm::MaybeAlign ExplicitAlignment;
diff --git a/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c b/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c
index baa02926d9bf7..2071e66e0d652 100644
--- a/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c
+++ b/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_FLATTEN -o - | FileCheck %s --check-prefix=CHECK-FLATTEN
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s --check-prefix=CHECK-ALWAYS-INLINE
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_FLATTEN -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s
// REQUIRES: aarch64-registered-target
@@ -31,26 +31,14 @@ void caller(void) {
STMT_ATTR fn_streaming_new_za();
STMT_ATTR fn_streaming_new_zt0();
}
-// For flatten: fn() and fn_streaming_compatible() are inlined, streaming functions
-// are blocked by TTI (non-streaming caller), new_za/new_zt0 are always blocked.
-// CHECK-FLATTEN-LABEL: void @caller()
-// CHECK-FLATTEN-NEXT: entry:
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @fn_streaming
-// CHECK-FLATTEN-NEXT: call void @fn_locally_streaming
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_za
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_zt0
-
-// For always_inline: Clang's wouldInliningViolateFunctionCallABI controls.
-// CHECK-ALWAYS-INLINE-LABEL: void @caller()
-// CHECK-ALWAYS-INLINE-NEXT: entry:
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_locally_streaming
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_za
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_zt0
+// CHECK-LABEL: void @caller()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @fn_streaming
+// CHECK-NEXT: call void @fn_locally_streaming
+// CHECK-NEXT: call void @fn_streaming_new_za
+// CHECK-NEXT: call void @fn_streaming_new_zt0
FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible {
STMT_ATTR fn();
@@ -60,26 +48,14 @@ FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible {
STMT_ATTR fn_streaming_new_za();
STMT_ATTR fn_streaming_new_zt0();
}
-// For flatten: TTI allows inlining fn(), fn_streaming_compatible(), fn_streaming(),
-// fn_locally_streaming() because they don't have incompatible ops. Only new_za/new_zt0 blocked.
-// CHECK-FLATTEN-LABEL: void @caller_streaming_compatible()
-// CHECK-FLATTEN-NEXT: entry:
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_za
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_zt0
-
-// For always_inline: Clang blocks fn() (streaming-compatible caller, non-streaming callee).
-// CHECK-ALWAYS-INLINE-LABEL: void @caller_streaming_compatible()
-// CHECK-ALWAYS-INLINE-NEXT: entry:
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_locally_streaming
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_za
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_zt0
+// CHECK-LABEL: void @caller_streaming_compatible()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @fn
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @fn_streaming
+// CHECK-NEXT: call void @fn_locally_streaming
+// CHECK-NEXT: call void @fn_streaming_new_za
+// CHECK-NEXT: call void @fn_streaming_new_zt0
FN_ATTR void caller_streaming(void) __arm_streaming {
STMT_ATTR fn();
@@ -89,26 +65,14 @@ FN_ATTR void caller_streaming(void) __arm_streaming {
STMT_ATTR fn_streaming_new_za();
STMT_ATTR fn_streaming_new_zt0();
}
-// For flatten: TTI allows all except new_za/new_zt0. fn() is inlined because
-// streaming caller can execute non-streaming callee's code (no incompatible ops).
-// CHECK-FLATTEN-LABEL: void @caller_streaming()
-// CHECK-FLATTEN-NEXT: entry:
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_za
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_zt0
-
-// For always_inline: Clang blocks fn() (streaming caller, non-streaming callee).
-// CHECK-ALWAYS-INLINE-LABEL: void @caller_streaming()
-// CHECK-ALWAYS-INLINE-NEXT: entry:
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_za
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_zt0
+// CHECK-LABEL: void @caller_streaming()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @fn
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @fn_streaming_new_za
+// CHECK-NEXT: call void @fn_streaming_new_zt0
FN_ATTR __arm_locally_streaming
void caller_locally_streaming(void) {
@@ -119,22 +83,11 @@ void caller_locally_streaming(void) {
STMT_ATTR fn_streaming_new_za();
STMT_ATTR fn_streaming_new_zt0();
}
-// For flatten: Similar to caller_streaming - TTI allows all except new_za/new_zt0.
-// CHECK-FLATTEN-LABEL: void @caller_locally_streaming()
-// CHECK-FLATTEN-NEXT: entry:
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @was_inlined
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_za
-// CHECK-FLATTEN-NEXT: call void @fn_streaming_new_zt0
-
-// For always_inline: Clang blocks fn().
-// CHECK-ALWAYS-INLINE-LABEL: void @caller_locally_streaming()
-// CHECK-ALWAYS-INLINE-NEXT: entry:
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @was_inlined
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_za
-// CHECK-ALWAYS-INLINE-NEXT: call void @fn_streaming_new_zt0
+// CHECK-LABEL: void @caller_locally_streaming()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @fn
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @was_inlined
+// CHECK-NEXT: call void @fn_streaming_new_za
+// CHECK-NEXT: call void @fn_streaming_new_zt0
diff --git a/clang/test/CodeGen/flatten.c b/clang/test/CodeGen/flatten.c
index 25cbcdb7fe0e1..4e762223de486 100644
--- a/clang/test/CodeGen/flatten.c
+++ b/clang/test/CodeGen/flatten.c
@@ -1,27 +1,19 @@
// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s
-// External functions to provide side effects that prevent trivial elimination.
-void external_f(void);
-void external_h(void);
+void f(void) {}
-void f(void) { external_f(); }
+__attribute__((noinline)) void ni(void) {}
-void h(void) {
- external_h();
- f();
-}
-
-// CHECK-LABEL: define{{.*}} void @g()
-// CHECK-SAME: [[FLATTEN_ATTR:#[0-9]+]]
__attribute__((flatten))
+// CHECK: define{{.*}} void @g()
void g(void) {
- // Flatten recursively inlines: g -> h -> f, so neither call remains.
- // Only the leaf external() call should survive.
- // CHECK-NOT: call {{.*}} @h
// CHECK-NOT: call {{.*}} @f
- // CHECK: call {{.*}} @external_h
- // CHECK: call {{.*}} @external_f
- h();
+ f();
+ // CHECK: call {{.*}} @ni
+ ni();
}
-// CHECK: attributes [[FLATTEN_ATTR]] = {{{.*}}flatten{{.*}}}
+void h(void) {
+ // CHECK: call {{.*}} @f
+ f();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/195314
More information about the cfe-commits
mailing list