Skip to content

[CodeGen][StaticDataSplitter]Support constant pool partitioning #129781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions llvm/include/llvm/CodeGen/AsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/StaticDataProfileInfo.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
Expand Down Expand Up @@ -132,6 +134,12 @@ class AsmPrinter : public MachineFunctionPass {
/// default, this is equal to CurrentFnSym.
MCSymbol *CurrentFnSymForSize = nullptr;

/// Provides the profile information for constants.
const StaticDataProfileInfo *SDPI = nullptr;

/// The profile summary information.
const ProfileSummaryInfo *PSI = nullptr;

/// Map a basic block section ID to the begin and end symbols of that section
/// which determine the section's range.
struct MBBSectionRange {
Expand Down Expand Up @@ -330,6 +338,10 @@ class AsmPrinter : public MachineFunctionPass {
DwarfUsesRelocationsAcrossSections = Enable;
}

/// Returns a section suffix (hot or unlikely) for the constant if profiles
/// are available. Returns empty string otherwise.
StringRef getConstantSectionSuffix(const Constant *C) const;

//===------------------------------------------------------------------===//
// XRay instrumentation implementation.
//===------------------------------------------------------------------===//
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
const Constant *C,
Align &Alignment) const override;

/// Similar to the function above, but append \p SectionSuffix to the section
/// name.
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
const Constant *C, Align &Alignment,
StringRef SectionSuffix) const override;

MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;

Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/Target/TargetLoweringObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
SectionKind Kind, const Constant *C,
Align &Alignment) const;

/// Similar to the function above, but append \p SectionSuffix to the section
/// name.
virtual MCSection *getSectionForConstant(const DataLayout &DL,
SectionKind Kind, const Constant *C,
Align &Alignment,
StringRef SectionSuffix) const;

virtual MCSection *
getSectionForMachineBasicBlock(const Function &F,
const MachineBasicBlock &MBB,
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2769,6 +2769,13 @@ namespace {

} // end anonymous namespace

StringRef AsmPrinter::getConstantSectionSuffix(const Constant *C) const {
if (TM.Options.EnableStaticDataPartitioning && C && SDPI && PSI)
return SDPI->getConstantSectionPrefix(C, PSI);

return "";
}

/// EmitConstantPool - Print to the current output stream assembly
/// representations of the constants in the constant pool MCP. This is
/// used to print out constants which have been "spilled to memory" by
Expand All @@ -2792,7 +2799,7 @@ void AsmPrinter::emitConstantPool() {
C = CPE.Val.ConstVal;

MCSection *S = getObjFileLowering().getSectionForConstant(
getDataLayout(), Kind, C, Alignment);
getDataLayout(), Kind, C, Alignment, getConstantSectionSuffix(C));

// The number of sections are small, just do a linear search from the
// last section to the first.
Expand Down
82 changes: 55 additions & 27 deletions llvm/lib/CodeGen/StaticDataSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// for the following types of static data:
// - Jump tables
// - Module-internal global variables
// - Constant pools (TODO)
// - Constant pools
//
// For the original RFC of this pass please see
// https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744
Expand Down Expand Up @@ -60,8 +60,8 @@ class StaticDataSplitter : public MachineFunctionPass {

// Returns the constant if the operand refers to a global variable or constant
// that gets lowered to static data sections. Otherwise, return nullptr.
const Constant *getConstant(const MachineOperand &Op,
const TargetMachine &TM);
const Constant *getConstant(const MachineOperand &Op, const TargetMachine &TM,
const MachineConstantPool *MCP);

// Use profiles to partition static data.
bool partitionStaticDataWithProfiles(MachineFunction &MF);
Expand Down Expand Up @@ -89,8 +89,11 @@ class StaticDataSplitter : public MachineFunctionPass {
AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
AU.addRequired<ProfileSummaryInfoWrapperPass>();
AU.addRequired<StaticDataProfileInfoWrapperPass>();
// This pass does not modify the CFG.
AU.setPreservesCFG();
// This pass does not modify any required analysis results except
// StaticDataProfileInfoWrapperPass, but StaticDataProfileInfoWrapperPass
// is made an immutable pass that it won't be re-scheduled by pass manager
// anyway. So mark setPreservesAll() here for faster compile time.
AU.setPreservesAll();
}

bool runOnMachineFunction(MachineFunction &MF) override;
Expand Down Expand Up @@ -119,40 +122,63 @@ bool StaticDataSplitter::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}

const Constant *StaticDataSplitter::getConstant(const MachineOperand &Op,
const TargetMachine &TM) {
if (!Op.isGlobal())
const Constant *
StaticDataSplitter::getConstant(const MachineOperand &Op,
const TargetMachine &TM,
const MachineConstantPool *MCP) {
if (!Op.isGlobal() && !Op.isCPI())
return nullptr;

// Find global variables with local linkage.
const GlobalVariable *GV = getLocalLinkageGlobalVariable(Op.getGlobal());
// Skip 'llvm.'-prefixed global variables conservatively because they are
// often handled specially, and skip those not in static data sections.
if (!GV || GV->getName().starts_with("llvm.") ||
!inStaticDataSection(*GV, TM))
if (Op.isGlobal()) {
// Find global variables with local linkage.
const GlobalVariable *GV = getLocalLinkageGlobalVariable(Op.getGlobal());
// Skip 'llvm.'-prefixed global variables conservatively because they are
// often handled specially, and skip those not in static data
// sections.
if (!GV || GV->getName().starts_with("llvm.") ||
!inStaticDataSection(*GV, TM))
return nullptr;
return GV;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation to handle "GlobalVariable" here? Any test to cover it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global variable handling should be a part of #125756, so did it in 9302b2b

}
assert(Op.isCPI() && "Op must be constant pool index in this branch");
int CPI = Op.getIndex();
if (CPI == -1)
return nullptr;

assert(MCP != nullptr && "Constant pool info is not available.");
const MachineConstantPoolEntry &CPE = MCP->getConstants()[CPI];

if (CPE.isMachineConstantPoolEntry())
return nullptr;
return GV;

return CPE.Val.ConstVal;
}

bool StaticDataSplitter::partitionStaticDataWithProfiles(MachineFunction &MF) {
int NumChangedJumpTables = 0;
// If any of the static data (jump tables, global variables, constant pools)
// are captured by the analysis, set `Changed` to true. Note this pass won't
// invalidate any analysis pass (see `getAnalysisUsage` above), so the main
// purpose of tracking and conveying the change (to pass manager) is
// informative as opposed to invalidating any analysis results. As an example
// of where this information is useful, `PMDataManager::dumpPassInfo` will
// only dump pass info if a local change happens, otherwise a pass appears as
// "skipped".
bool Changed = false;

const TargetMachine &TM = MF.getTarget();
MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();

// Jump table could be used by either terminating instructions or
// non-terminating ones, so we walk all instructions and use
// `MachineOperand::isJTI()` to identify jump table operands.
// Similarly, `MachineOperand::isCPI()` can identify constant pool usages
// in the same loop.
// Similarly, `MachineOperand::isCPI()` is used to identify constant pool
// usages in the same loop.
for (const auto &MBB : MF) {
std::optional<uint64_t> Count = MBFI->getBlockProfileCount(&MBB);
for (const MachineInstr &I : MBB) {
for (const MachineOperand &Op : I.operands()) {
if (!Op.isJTI() && !Op.isGlobal())
if (!Op.isJTI() && !Op.isGlobal() && !Op.isCPI())
continue;

std::optional<uint64_t> Count = MBFI->getBlockProfileCount(&MBB);

if (Op.isJTI()) {
assert(MJTI != nullptr && "Jump table info is not available.");
const int JTI = Op.getIndex();
Expand All @@ -168,15 +194,16 @@ bool StaticDataSplitter::partitionStaticDataWithProfiles(MachineFunction &MF) {
if (Count && PSI->isColdCount(*Count))
Hotness = MachineFunctionDataHotness::Cold;

if (MJTI->updateJumpTableEntryHotness(JTI, Hotness))
++NumChangedJumpTables;
} else if (const Constant *C = getConstant(Op, TM)) {
Changed |= MJTI->updateJumpTableEntryHotness(JTI, Hotness);
} else if (const Constant *C =
getConstant(Op, MF.getTarget(), MF.getConstantPool())) {
SDPI->addConstantProfileCount(C, Count);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we don't need to update "NumChangedJumpTables" here. but why do we need to return "true" or "false" for this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Or rather, why do StaticDataSplitter pass return 'true' or 'false` to pass manager?

Notably,

  1. For the StaticdataSplitter pass, none of the data structures (MachineJumpTableInfo or immutable pass StaticDataProfileInfoWrapperPass) touched by this pass are tracked by its mutable, required analysis, and by definition of pass manager, it means it's correct to say call setPreservesAll for this pass.
  2. For faster compile time, we want subsequent passes to reuse analysis result (of mutable passes) as much as possible rather than re-computing them, since the analysis result are not mutated by this pass. Also pass manager won't automatically re-schedule (or re-compute) an immutable pass whether a transformation pass returns true or false.

I think the return value is mainly for informative purposes. More specifically, pass manager can dump [2] pass execution history (presumably when people are debugging something), when

  1. -debug-pass is specified as Executions or higher [1] (e.g., for opt, llc or clang -mllvm -debug-pass=<xxx>)
  2. a pass return true which makes [LocalChanged](https://github.com/llvm/llvm-project/blob/ecaef010f31e2557d94b4d98774ca4b4d5fe2149/llvm/lib/IR/LegacyPassManager.cpp#L1406) true,

Upon this comment and discussion, I made two code changes (along with comments)

  1. In getAnalysisUsage (at line 87 - 97) to call setPreservesAll()
  2. In partitionStaticDataWithProfiles, changed int NumChangedJumpTables to bool Changed, and make it track both jump table and constant changes. How does this look?

[1]

if (PassDebugging < Executions)
return;

[2]
if (LocalChanged)
dumpPassInfo(FP, MODIFICATION_MSG, ON_FUNCTION_MSG, Name);

Changed = true;
}
}
}
}
return NumChangedJumpTables > 0;
return Changed;
}

const GlobalVariable *
Expand Down Expand Up @@ -218,7 +245,8 @@ void StaticDataSplitter::annotateStaticDataWithoutProfiles(
for (const auto &MBB : MF)
for (const MachineInstr &I : MBB)
for (const MachineOperand &Op : I.operands())
if (const Constant *C = getConstant(Op, MF.getTarget()))
if (const Constant *C =
getConstant(Op, MF.getTarget(), MF.getConstantPool()))
SDPI->addConstantProfileCount(C, std::nullopt);
}

Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,41 @@ MCSection *TargetLoweringObjectFileELF::getSectionForConstant(
return DataRelROSection;
}

MCSection *TargetLoweringObjectFileELF::getSectionForConstant(
const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment,
StringRef SectionSuffix) const {
// TODO: Share code between this function and
// MCObjectInfo::initELFMCObjectFileInfo.
if (SectionSuffix.empty())
return getSectionForConstant(DL, Kind, C, Alignment);

auto &Context = getContext();
if (Kind.isMergeableConst4() && MergeableConst4Section)
return Context.getELFSection(".rodata.cst4." + SectionSuffix,
ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_MERGE, 4);
if (Kind.isMergeableConst8() && MergeableConst8Section)
return Context.getELFSection(".rodata.cst8." + SectionSuffix,
ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_MERGE, 8);
if (Kind.isMergeableConst16() && MergeableConst16Section)
return Context.getELFSection(".rodata.cst16." + SectionSuffix,
ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_MERGE, 16);
if (Kind.isMergeableConst32() && MergeableConst32Section)
return Context.getELFSection(".rodata.cst32." + SectionSuffix,
ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_MERGE, 32);
if (Kind.isReadOnly())
return Context.getELFSection(".rodata." + SectionSuffix, ELF::SHT_PROGBITS,
ELF::SHF_ALLOC);

assert(Kind.isReadOnlyWithRel() && "Unknown section kind");
return Context.getELFSection(".data.rel.ro." + SectionSuffix,
ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_WRITE);
}

/// Returns a unique section for the given machine basic block.
MCSection *TargetLoweringObjectFileELF::getSectionForMachineBasicBlock(
const Function &F, const MachineBasicBlock &MBB,
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ class AArch64AsmPrinter : public AsmPrinter {
}

bool runOnMachineFunction(MachineFunction &MF) override {
if (auto *PSIW = getAnalysisIfAvailable<ProfileSummaryInfoWrapperPass>())
PSI = &PSIW->getPSI();
if (auto *SDPIW =
getAnalysisIfAvailable<StaticDataProfileInfoWrapperPass>())
SDPI = &SDPIW->getStaticDataProfileInfo();

AArch64FI = MF.getInfo<AArch64FunctionInfo>();
STI = &MF.getSubtarget<AArch64Subtarget>();

Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/TargetLoweringObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,18 @@ MCSection *TargetLoweringObjectFile::getSectionForConstant(
return DataSection;
}

MCSection *TargetLoweringObjectFile::getSectionForConstant(
const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment,
StringRef SectionPrefix) const {
// Fallback to `getSectionForConstant` without `SectionPrefix` parameter if it
// is empty.
if (SectionPrefix.empty())
return getSectionForConstant(DL, Kind, C, Alignment);
report_fatal_error(
"TargetLoweringObjectFile::getSectionForConstant that "
"accepts SectionPrefix is not implemented for the object file format");
}

MCSection *TargetLoweringObjectFile::getSectionForMachineBasicBlock(
const Function &F, const MachineBasicBlock &MBB,
const TargetMachine &TM) const {
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/X86/X86AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
#include "X86Subtarget.h"
#include "llvm/Analysis/StaticDataProfileInfo.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CodeGen/MachineConstantPool.h"
Expand Down Expand Up @@ -61,6 +62,11 @@ X86AsmPrinter::X86AsmPrinter(TargetMachine &TM,
/// runOnMachineFunction - Emit the function body.
///
bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
if (auto *PSIW = getAnalysisIfAvailable<ProfileSummaryInfoWrapperPass>())
PSI = &PSIW->getPSI();
if (auto *SDPIW = getAnalysisIfAvailable<StaticDataProfileInfoWrapperPass>())
SDPI = &SDPIW->getStaticDataProfileInfo();

Subtarget = &MF.getSubtarget<X86Subtarget>();

SMShadowTracker.startFunction(MF);
Expand Down
Loading