llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Cs137 (Jiang-XueZhi)

<details>
<summary>Changes</summary>

Fix #<!-- -->133246

Emit `__attribute__((constructor))` functions into `.text.startup` and 
`__attribute__((destructor))` functions into `.text.exit` on ELF targets, 
matching GCC's behavior.

GCC groups constructor functions in `.text.startup` and destructor functions in 
`.text.exit`. This improves memory utilization at runtime:

- Startup-only code is aggregated into a contiguous region, allowing the 
operating system to load it as a unit during initialization and subsequently 
reclaim those pages.
- Exit-only code is similarly isolated, preventing it from polluting the hot 
code path.
- ibache utilization is improved because code that runs only once (at startup 
or exit) does not displace frequently-executed code from the instruction cache.

Clang currently places both constructor and destructor attribute functions in 
the generic `.text` section alongside all other code, losing this optimization 
opportunity entirely.

In systems with many constructor attribute functions, this fragmentation causes 
measurable memory pressure: constructor bodies scattered throughout `.text` 
remain resident long after initialization completes, increasing the resident 
set size and the risk of future page faults.

---
Full diff: https://github.com/llvm/llvm-project/pull/200221.diff


2 Files Affected:

- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+15) 
- (added) clang/test/CodeGen/constructor-section-prefix.c (+28) 


``````````diff
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index b8841f75a5c19..741252df74acc 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6860,6 +6860,18 @@ void 
CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
   EmitTopLevelDecl(VD);
 }
 
+/// Return the ELF section prefix for a function based on the function's
+/// code-region affinity: "startup" for functions that run exclusively at
+/// program startup, "exit" for functions that run exclusively at program
+/// exit. Returns nullptr when the function has no such affinity.
+static const char *getCodeRegionSectionPrefix(const FunctionDecl *D) {
+  if (D->hasAttr<ConstructorAttr>())
+    return "startup";
+  if (D->hasAttr<DestructorAttr>())
+    return "exit";
+  return nullptr;
+}
+
 void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
                                                  llvm::GlobalValue *GV) {
   const auto *D = cast<FunctionDecl>(GD.getDecl());
@@ -6929,6 +6941,9 @@ void 
CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
     AddGlobalCtor(Fn, GetPriority(CA));
   if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
     AddGlobalDtor(Fn, GetPriority(DA), true);
+  if (!Fn->hasSection())
+    if (const char *Prefix = getCodeRegionSectionPrefix(D))
+      Fn->setSectionPrefix(Prefix);
   if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
     getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
 }
diff --git a/clang/test/CodeGen/constructor-section-prefix.c 
b/clang/test/CodeGen/constructor-section-prefix.c
new file mode 100644
index 0000000000000..851092d69d474
--- /dev/null
+++ b/clang/test/CodeGen/constructor-section-prefix.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck 
--check-prefix=CHECK-IR %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -S -ffunction-sections %s -o - | 
FileCheck --check-prefix=CHECK-ASM %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck 
--check-prefix=CHECK-EXPLICIT %s
+
+// CHECK-IR: define{{.*}} void @plain_ctor(){{.*}} !section_prefix 
![[CTOR:[0-9]+]]
+// CHECK-IR: define{{.*}} void @plain_dtor(){{.*}} !section_prefix 
![[DTOR:[0-9]+]]
+// CHECK-IR: define{{.*}} void @ctor_prio(){{.*}} !section_prefix ![[CTOR]]
+// CHECK-IR: define{{.*}} void @dtor_prio(){{.*}} !section_prefix ![[DTOR]]
+// CHECK-IR: ![[CTOR]] = !{!"section_prefix", !"startup"}
+// CHECK-IR: ![[DTOR]] = !{!"section_prefix", !"exit"}
+
+// CHECK-ASM: .section .text.startup.plain_ctor,"ax",@progbits
+// CHECK-ASM: .section .text.exit.plain_dtor,"ax",@progbits
+// CHECK-ASM: .section .text.startup.ctor_prio,"ax",@progbits
+// CHECK-ASM: .section .text.exit.dtor_prio,"ax",@progbits
+
+// CHECK-EXPLICIT: define{{.*}} void @ctor_explicit_section(){{.*}} section 
".my_section"
+// CHECK-EXPLICIT-NOT: define{{.*}} void @ctor_explicit_section(){{.*}} 
section_prefix
+
+void __attribute__((constructor)) plain_ctor(void) {}
+
+void __attribute__((destructor)) plain_dtor(void) {}
+
+void __attribute__((constructor(101))) ctor_prio(void) {}
+
+void __attribute__((destructor(202))) dtor_prio(void) {}
+
+void __attribute__((constructor, section(".my_section"))) 
ctor_explicit_section(void) {}

``````````

</details>


https://github.com/llvm/llvm-project/pull/200221
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to