[llvm] [CodeGen][StaticDataPartitioning]Place local-linkage global variables in hot or unlikely prefixed sections based on profile information (PR #125756)

Mingming Liu via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 7 17:45:24 PST 2025


================
@@ -117,18 +142,89 @@ bool StaticDataSplitter::partitionStaticDataWithProfiles(MachineFunction &MF) {
           // Hotness is based on source basic block hotness.
           // TODO: PSI APIs are about instruction hotness. Introduce API for
           // data access hotness.
-          if (PSI->isColdBlock(&MBB, MBFI))
+          if (Count && PSI->isColdCount(*Count))
             Hotness = MachineFunctionDataHotness::Cold;
 
           if (MJTI->updateJumpTableEntryHotness(JTI, Hotness))
             ++NumChangedJumpTables;
+        } else if (Op.isGlobal()) {
+          // Find global variables with local linkage
+          const GlobalVariable *GV =
+              getLocalLinkageGlobalVariable(Op.getGlobal());
+          if (!GV || !inStaticDataSection(GV, TM))
+            continue;
+
+          // Acccumulate data profile count across machine function
+          // instructions.
+          // TODO: Analyze global variable's initializers.
+          if (Count) {
+            auto [It, Inserted] =
+                DataProfileCounts.try_emplace(GV, APInt(128, 0));
+            It->second += *Count;
+          }
         }
       }
     }
   }
   return NumChangedJumpTables > 0;
 }
 
+const GlobalVariable *
+StaticDataSplitter::getLocalLinkageGlobalVariable(const GlobalValue *GV) {
+  if (!GV || GV->isDeclarationForLinker())
+    return nullptr;
+
+  return GV->hasLocalLinkage() ? dyn_cast<GlobalVariable>(GV) : nullptr;
+}
+
+bool StaticDataSplitter::inStaticDataSection(const GlobalVariable *GV,
+                                             const TargetMachine &TM) {
+  assert(GV && "Caller guaranteed");
+
+  // Skip LLVM reserved symbols.
+  if (GV->getName().starts_with("llvm."))
+    return false;
+
+  SectionKind Kind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);
+  return Kind.isData() || Kind.isReadOnly() || Kind.isReadOnlyWithRel() ||
+         Kind.isBSS();
+}
+
+bool StaticDataSplitter::updateGlobalVariableSectionPrefix(
+    MachineFunction &MF) {
+  bool Changed = false;
+  for (GlobalVariable &GV : MF.getFunction().getParent()->globals()) {
+    if (GV.isDeclarationForLinker())
+      continue;
+    // DataProfileCounts accumulates data profile count across all machine
+    // function instructions, and it can't model the indirect accesses through
+    // other global variables' initializers.
+    // TODO: Analyze the users of module-internal global variables and see
+    // through the users' initializers. Do not place a global variable into
+    // unlikely section if any of its users are potentially hot.
+    auto Iter = DataProfileCounts.find(&GV);
+    if (Iter == DataProfileCounts.end())
+      continue;
+
+    // StaticDataSplitter is made a machine function pass rather than a module
+    // pass because (Lazy)MachineBlockFrequencyInfo is a machine-function
+    // analysis pass and cannot be used for a legacy module pass.
+    // As a result, we use `DataProfileCounts` to accumulate data
+    // profile count across machine functions and update global variable section
+    // prefix once per machine function.
+    // FIXME: Make StaticDataSplitter a module pass under new pass manager
+    // framework, and set global variable section prefix once per module after
+    // analyzing all machine functions.
+    if (PSI->isColdCount(Iter->second.getZExtValue())) {
+      Changed |= GV.updateSectionPrefix("unlikely",
----------------
mingmingl-llvm wrote:

My understanding is that functions have `.hot` or `.unlikely` prefixes when they are placed as a whole (in the [codegenprepare](https://github.com/llvm/llvm-project/blob/69ccb1357fa6cf72063c737d06d6b29ffc465bee/llvm/lib/CodeGen/CodeGenPrepare.cpp#L598) pass), and have `.split` as a prefix when basic blocks of a function are further categorized into hot and non-hot ones (in the [MFS](https://github.com/llvm/llvm-project/blob/69ccb1357fa6cf72063c737d06d6b29ffc465bee/llvm/lib/CodeGen/MachineFunctionSplitter.cpp#L12-L14) pass you mentioned).

Here the granularity is a piece of global variable, and `.split` would be a good name if a global variable itself is split into hot and cold ones. For instance, there should be hot and cold functions in a vtable, but it'd take substantial work to implement an ABI to support the split vtable entries.

https://github.com/llvm/llvm-project/pull/125756


More information about the llvm-commits mailing list