[clang] [CIR] Correct the behavior of 'shouldEmitFunction' with always/noinline (PR #224378)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 17 11:05:31 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Erich Keane (erichkeane)
<details>
<summary>Changes</summary>
These attributes modified the linkage of functions in certain cases that caused us to, ironically, skip emitting something when we picked it up via PCH during self-build. This patch just copies/pastes the code from classic codegen.
---
Full diff: https://github.com/llvm/llvm-project/pull/224378.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+14)
- (added) clang/test/CIR/CodeGen/noinline-available-externally-skip.cpp (+51)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 3af6ce4ce6e94..03a799ccc74f1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1705,6 +1705,20 @@ bool CIRGenModule::shouldEmitFunction(GlobalDecl gd) {
if (fd->isInlineBuiltinDeclaration())
return true;
+ if (codeGenOpts.OptimizationLevel == 0 && !fd->hasAttr<AlwaysInlineAttr>())
+ return false;
+
+ // We don't import function bodies from other named module units since that
+ // behavior may break ABI compatibility of the current unit.
+ if (const Module *m = fd->getOwningModule();
+ m && m->getTopLevelModule()->isNamedModule() &&
+ getASTContext().getCurrentNamedModule() != m->getTopLevelModule()) {
+ errorNYI(fd->getSourceRange(), "should emit function in a named module");
+ }
+
+ if (fd->hasAttr<NoInlineAttr>())
+ return false;
+
// PR9614 / glibc btowc workaround: an available_externally function whose
// body just calls itself (via asm label or __builtin_* lowering on the
// same name) is not a valid stand-in for the real implementation. Drop
diff --git a/clang/test/CIR/CodeGen/noinline-available-externally-skip.cpp b/clang/test/CIR/CodeGen/noinline-available-externally-skip.cpp
new file mode 100644
index 0000000000000..0a7821c61c150
--- /dev/null
+++ b/clang/test/CIR/CodeGen/noinline-available-externally-skip.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -O0 -disable-llvm-passes -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIRO0
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -O0 -disable-llvm-passes -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM,LLVMO0
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -disable-llvm-passes -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM,LLVMO0
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -O2 -disable-llvm-passes -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIRO2
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -O2 -disable-llvm-passes -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM,LLVMO2
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -disable-llvm-passes -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM,LLVMO2
+
+template <typename T>
+class Holder {
+ T val;
+public:
+ explicit Holder(T v) : val(v) {}
+ // NOT defined.
+ // CIR-DAG: cir.func private @_ZNK6HolderIiE4dumpEv{{.*}}attributes {{{.*}}}{{[^{]*}}{{$}}
+ // LLVM-DAG: declare void @_ZNK6HolderIiE4dumpEv
+ __attribute__((noinline)) void dump() const {}
+
+ // ONLY defined in O2:
+ // CIRO0-DAG: cir.func private @_ZNK6HolderIiE4showEv{{.*}}attributes {{{.*}}}{{[^{]*}}{{$}}
+ // CIRO2-DAG: cir.func available_externally @_ZNK6HolderIiE4showEv{{.*}}attributes {{{.*}}} {
+ // LLVMO0-DAG: declare void @_ZNK6HolderIiE4showEv
+ // LLVMO2-DAG: define available_externally void @_ZNK6HolderIiE4showEv
+ void show() const {}
+
+ // CIR-DAG: cir.func always_inline available_externally @_ZNK6HolderIiE18dump_always_inlineEv{{.*}}attributes {{{.*}}} {
+ // LLVM-DAG: define available_externally void @_ZNK6HolderIiE18dump_always_inlineEv
+ __attribute__((always_inline)) void dump_always_inline() const {}
+};
+
+// Suppresses instantiation in this TU; dump() and show() are available_externally.
+extern template class Holder<int>;
+
+// Normal Definition (wildcard is no_inline, added in O0)
+// CIR-DAG: cir.func {{.*}}dso_local @_Z6callerP6HolderIiE{{.*}} attributes {{{.*}}} {
+// LLVM-DAG: define {{.*}}dso_local void @_Z6callerP6HolderIiE
+void caller(Holder<int> *h) {
+ h->dump_always_inline();
+ h->dump();
+ h->show();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/224378
More information about the cfe-commits
mailing list