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
