https://github.com/mingmingl-llvm created https://github.com/llvm/llvm-project/pull/122215
None >From a2a6f9f5a6f7647f85a230241bf3aa39c4bd65d9 Mon Sep 17 00:00:00 2001 From: mingmingl <mingmi...@google.com> Date: Wed, 8 Jan 2025 16:53:45 -0800 Subject: [PATCH] [AsmPrinter][TargetLowering]Place a hot jump table into a hot-suffixed section --- llvm/include/llvm/CodeGen/AsmPrinter.h | 8 +- .../CodeGen/TargetLoweringObjectFileImpl.h | 3 + .../llvm/Target/TargetLoweringObjectFile.h | 5 + llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 102 +++++++++++++----- .../CodeGen/TargetLoweringObjectFileImpl.cpp | 28 +++-- llvm/lib/CodeGen/TargetPassConfig.cpp | 8 +- llvm/lib/Target/TargetLoweringObjectFile.cpp | 6 ++ llvm/test/CodeGen/X86/jump-table-partition.ll | 8 +- 8 files changed, 130 insertions(+), 38 deletions(-) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index c9a88d7b1c015c..9249d5adf3f6f7 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -453,6 +453,10 @@ class AsmPrinter : public MachineFunctionPass { /// function to the current output stream. virtual void emitJumpTableInfo(); + virtual void emitJumpTables(const std::vector<unsigned> &JumpTableIndices, + MCSection *JumpTableSection, bool JTInDiffSection, + const MachineJumpTableInfo &MJTI); + /// Emit the specified global variable to the .s file. virtual void emitGlobalVariable(const GlobalVariable *GV); @@ -892,10 +896,10 @@ class AsmPrinter : public MachineFunctionPass { // Internal Implementation Details //===------------------------------------------------------------------===// - void emitJumpTableEntry(const MachineJumpTableInfo *MJTI, + void emitJumpTableEntry(const MachineJumpTableInfo &MJTI, const MachineBasicBlock *MBB, unsigned uid) const; - void emitJumpTableSizesSection(const MachineJumpTableInfo *MJTI, + void emitJumpTableSizesSection(const MachineJumpTableInfo &MJTI, const Function &F) const; void emitLLVMUsedList(const ConstantArray *InitList); diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index a2a9e5d499e527..3d48d380fcb245 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -74,6 +74,9 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { MCSection *getSectionForJumpTable(const Function &F, const TargetMachine &TM) const override; + MCSection * + getSectionForJumpTable(const Function &F, const TargetMachine &TM, + const MachineJumpTableEntry *JTE) const override; MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const override; diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 4864ba843f4886..577adc458fcbf1 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -27,6 +27,7 @@ class Function; class GlobalObject; class GlobalValue; class MachineBasicBlock; +class MachineJumpTableEntry; class MachineModuleInfo; class Mangler; class MCContext; @@ -132,6 +133,10 @@ class TargetLoweringObjectFile : public MCObjectFileInfo { virtual MCSection *getSectionForJumpTable(const Function &F, const TargetMachine &TM) const; + virtual MCSection * + getSectionForJumpTable(const Function &F, const TargetMachine &TM, + const MachineJumpTableEntry *JTE) const; + virtual MCSection *getSectionForLSDA(const Function &, const MCSymbol &, const TargetMachine &) const { return LSDASection; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d34fe0e86c7495..b575cd7d993c39 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -168,6 +168,11 @@ static cl::opt<bool> BBAddrMapSkipEmitBBEntries( "unnecessary for some PGOAnalysisMap features."), cl::Hidden, cl::init(false)); +static cl::opt<bool> + EmitStaticDataHotnessSuffix("emit-static-data-hotness-suffix", cl::Hidden, + cl::init(false), cl::ZeroOrMore, + cl::desc("Emit static data hotness suffix")); + static cl::opt<bool> EmitJumpTableSizesSection( "emit-jump-table-sizes-section", cl::desc("Emit a section containing jump table addresses and sizes"), @@ -2861,7 +2866,6 @@ void AsmPrinter::emitConstantPool() { // Print assembly representations of the jump tables used by the current // function. void AsmPrinter::emitJumpTableInfo() { - const DataLayout &DL = MF->getDataLayout(); const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); if (!MJTI) return; if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_Inline) return; @@ -2876,42 +2880,88 @@ void AsmPrinter::emitJumpTableInfo() { MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 || MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference64, F); + + if (!EmitStaticDataHotnessSuffix) { + std::vector<unsigned> JumpTableIndices; + for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) + JumpTableIndices.push_back(JTI); + // Prior code in this function verifies JT is not empty. Use JT[0] directly. + emitJumpTables(JumpTableIndices, TLOF.getSectionForJumpTable(F, TM), + JTInDiffSection, *MJTI); + return; + } + + // Iterate all jump tables, put them into two vectors, hot and lukewarm + std::vector<unsigned> HotOrWarmJumpTableIndices, ColdJumpTableIndices; + + for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) { + if (JT[JTI].Hotness == llvm::DataHotness::Cold) + ColdJumpTableIndices.push_back(JTI); + else + HotOrWarmJumpTableIndices.push_back(JTI); + } + + if (!HotOrWarmJumpTableIndices.empty()) + emitJumpTables(HotOrWarmJumpTableIndices, + TLOF.getSectionForJumpTable( + F, TM, &JT[*HotOrWarmJumpTableIndices.begin()]), + JTInDiffSection, *MJTI); + + if (!ColdJumpTableIndices.empty()) + emitJumpTables( + ColdJumpTableIndices, + TLOF.getSectionForJumpTable(F, TM, &JT[*ColdJumpTableIndices.begin()]), + JTInDiffSection, *MJTI); + + return; +} + +void AsmPrinter::emitJumpTables(const std::vector<unsigned> &JumpTableIndices, + MCSection *JumpTableSection, + bool JTInDiffSection, + const MachineJumpTableInfo &MJTI) { + if (JumpTableIndices.empty()) + return; + + const DataLayout &DL = MF->getDataLayout(); if (JTInDiffSection) { - // Drop it in the readonly section. - MCSection *ReadOnlySection = TLOF.getSectionForJumpTable(F, TM); - OutStreamer->switchSection(ReadOnlySection); + OutStreamer->switchSection(JumpTableSection); } - emitAlignment(Align(MJTI->getEntryAlignment(DL))); + emitAlignment(Align(MJTI.getEntryAlignment(MF->getDataLayout()))); // Jump tables in code sections are marked with a data_region directive // where that's supported. if (!JTInDiffSection) OutStreamer->emitDataRegion(MCDR_DataRegionJT32); - for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) { - const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; + const auto &JT = MJTI.getJumpTables(); + for (unsigned Index = 0, e = JumpTableIndices.size(); Index != e; ++Index) { + const std::vector<MachineBasicBlock *> &JTBBs = + JT[JumpTableIndices[Index]].MBBs; // If this jump table was deleted, ignore it. - if (JTBBs.empty()) continue; + if (JTBBs.empty()) + continue; // For the EK_LabelDifference32 entry, if using .set avoids a relocation, /// emit a .set directive for each unique entry. - if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && + if (MJTI.getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && MAI->doesSetDirectiveSuppressReloc()) { - SmallPtrSet<const MachineBasicBlock*, 16> EmittedSets; + SmallPtrSet<const MachineBasicBlock *, 16> EmittedSets; const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); - const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF,JTI,OutContext); + const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr( + MF, JumpTableIndices[Index], OutContext); for (const MachineBasicBlock *MBB : JTBBs) { if (!EmittedSets.insert(MBB).second) continue; // .set LJTSet, LBB32-base const MCExpr *LHS = - MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); - OutStreamer->emitAssignment(GetJTSetSymbol(JTI, MBB->getNumber()), - MCBinaryExpr::createSub(LHS, Base, - OutContext)); + MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); + OutStreamer->emitAssignment( + GetJTSetSymbol(JumpTableIndices[Index], MBB->getNumber()), + MCBinaryExpr::createSub(LHS, Base, OutContext)); } } @@ -2923,27 +2973,27 @@ void AsmPrinter::emitJumpTableInfo() { // FIXME: This doesn't have to have any specific name, just any randomly // named and numbered local label started with 'l' would work. Simplify // GetJTISymbol. - OutStreamer->emitLabel(GetJTISymbol(JTI, true)); + OutStreamer->emitLabel(GetJTISymbol(JumpTableIndices[Index], true)); - MCSymbol* JTISymbol = GetJTISymbol(JTI); + MCSymbol *JTISymbol = GetJTISymbol(JumpTableIndices[Index]); OutStreamer->emitLabel(JTISymbol); // Defer MCAssembler based constant folding due to a performance issue. The // label differences will be evaluated at write time. for (const MachineBasicBlock *MBB : JTBBs) - emitJumpTableEntry(MJTI, MBB, JTI); + emitJumpTableEntry(MJTI, MBB, JumpTableIndices[Index]); } if (EmitJumpTableSizesSection) - emitJumpTableSizesSection(MJTI, F); + emitJumpTableSizesSection(MJTI, MF->getFunction()); if (!JTInDiffSection) OutStreamer->emitDataRegion(MCDR_DataRegionEnd); } -void AsmPrinter::emitJumpTableSizesSection(const MachineJumpTableInfo *MJTI, +void AsmPrinter::emitJumpTableSizesSection(const MachineJumpTableInfo &MJTI, const Function &F) const { - const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); + const std::vector<MachineJumpTableEntry> &JT = MJTI.getJumpTables(); if (JT.empty()) return; @@ -2991,17 +3041,17 @@ void AsmPrinter::emitJumpTableSizesSection(const MachineJumpTableInfo *MJTI, /// EmitJumpTableEntry - Emit a jump table entry for the specified MBB to the /// current stream. -void AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI, +void AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo &MJTI, const MachineBasicBlock *MBB, unsigned UID) const { assert(MBB && MBB->getNumber() >= 0 && "Invalid basic block"); const MCExpr *Value = nullptr; - switch (MJTI->getEntryKind()) { + switch (MJTI.getEntryKind()) { case MachineJumpTableInfo::EK_Inline: llvm_unreachable("Cannot emit EK_Inline jump table entry"); case MachineJumpTableInfo::EK_Custom32: Value = MF->getSubtarget().getTargetLowering()->LowerCustomJumpTableEntry( - MJTI, MBB, UID, OutContext); + &MJTI, MBB, UID, OutContext); break; case MachineJumpTableInfo::EK_BlockAddress: // EK_BlockAddress - Each entry is a plain address of block, e.g.: @@ -3035,7 +3085,7 @@ void AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI, // If the .set directive avoids relocations, this is emitted as: // .set L4_5_set_123, LBB123 - LJTI1_2 // .word L4_5_set_123 - if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && + if (MJTI.getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && MAI->doesSetDirectiveSuppressReloc()) { Value = MCSymbolRefExpr::create(GetJTSetSymbol(UID, MBB->getNumber()), OutContext); @@ -3051,7 +3101,7 @@ void AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI, assert(Value && "Unknown entry kind!"); - unsigned EntrySize = MJTI->getEntrySize(getDataLayout()); + unsigned EntrySize = MJTI.getEntrySize(getDataLayout()); OutStreamer->emitValue(Value, EntrySize); } diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index be243c0e74e9db..07ebfe7daef3b3 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/BasicBlockSectionUtils.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/Comdat.h" @@ -642,9 +643,11 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) { static SmallString<128> getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, - unsigned EntrySize, bool UniqueSectionName) { + unsigned EntrySize, bool UniqueSectionName, + const MachineJumpTableEntry *JTE) { SmallString<128> Name = getSectionPrefixForGlobal(Kind, TM.isLargeGlobalValue(GO)); + if (Kind.isMergeableCString()) { // We also need alignment here. // FIXME: this is getting the alignment of the character, not the @@ -663,7 +666,11 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind, bool HasPrefix = false; if (const auto *F = dyn_cast<Function>(GO)) { - if (std::optional<StringRef> Prefix = F->getSectionPrefix()) { + // Jump table hotness takes precedence over its enclosing function's hotness + // if both are available. + if (JTE && JTE->Hotness == DataHotness::Hot) + raw_svector_ostream(Name) << ".hot"; + else if (std::optional<StringRef> Prefix = F->getSectionPrefix()) { raw_svector_ostream(Name) << '.' << *Prefix; HasPrefix = true; } @@ -761,8 +768,8 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName, // implicitly for this symbol e.g. .rodata.str1.1, then we don't need // to unique the section as the entry size for this symbol will be // compatible with implicitly created sections. - SmallString<128> ImplicitSectionNameStem = - getELFSectionNameForGlobal(GO, Kind, Mang, TM, EntrySize, false); + SmallString<128> ImplicitSectionNameStem = getELFSectionNameForGlobal( + GO, Kind, Mang, TM, EntrySize, false, /*MJTE=*/nullptr); if (SymbolMergeable && Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) && SectionName.starts_with(ImplicitSectionNameStem)) @@ -862,7 +869,8 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal( static MCSectionELF *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, - unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) { + unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol, + const MachineJumpTableEntry *MJTE = nullptr) { auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM); Flags |= ExtraFlags; @@ -881,7 +889,7 @@ static MCSectionELF *selectELFSectionForGlobal( } } SmallString<128> Name = getELFSectionNameForGlobal( - GO, Kind, Mang, TM, EntrySize, UniqueSectionName); + GO, Kind, Mang, TM, EntrySize, UniqueSectionName, MJTE); // Use 0 as the unique ID for execute-only text. if (Kind.isExecuteOnly()) @@ -955,6 +963,12 @@ MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction( MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( const Function &F, const TargetMachine &TM) const { + return getSectionForJumpTable(F, TM, nullptr); +} + +MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( + const Function &F, const TargetMachine &TM, + const MachineJumpTableEntry *JTE) const { // If the function can be removed, produce a unique section so that // the table doesn't prevent the removal. const Comdat *C = F.getComdat(); @@ -965,7 +979,7 @@ MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(), getMangler(), TM, EmitUniqueSection, ELF::SHF_ALLOC, &NextUniqueID, - /* AssociatedSymbol */ nullptr); + /* AssociatedSymbol */ nullptr, JTE); } MCSection *TargetLoweringObjectFileELF::getSectionForLSDA( diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 23929672f11d68..bf5ac140d7406a 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -263,6 +263,11 @@ static cl::opt<bool> GCEmptyBlocks("gc-empty-basic-blocks", cl::init(false), cl::Hidden, cl::desc("Enable garbage-collecting empty basic blocks")); +/// Enable the static data splitter pass. +static cl::opt<bool> SplitStaticData( + "split-static-data", cl::Hidden, cl::init(false), + cl::desc("Split static data sections using profile information")); + /// Allow standard passes to be disabled by command line options. This supports /// simple binary flags that either suppress the pass or do nothing. /// i.e. -disable-mypass=false has no effect. @@ -1256,8 +1261,9 @@ void TargetPassConfig::addMachinePasses() { "performance.\n"; } } - addPass(createStaticDataSplitterPass()); addPass(createMachineFunctionSplitterPass()); + if (SplitStaticData) + addPass(createStaticDataSplitterPass()); } // We run the BasicBlockSections pass if either we need BB sections or BB // address map (or both). diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp index 4fe9d13d062265..f21f72ad41e98e 100644 --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -348,6 +348,12 @@ TargetLoweringObjectFile::SectionForGlobal(const GlobalObject *GO, MCSection *TargetLoweringObjectFile::getSectionForJumpTable( const Function &F, const TargetMachine &TM) const { + return getSectionForJumpTable(F, TM, nullptr); +} + +MCSection *TargetLoweringObjectFile::getSectionForJumpTable( + const Function &F, const TargetMachine &TM, + const MachineJumpTableEntry *JTE) const { Align Alignment(1); return getSectionForConstant(F.getDataLayout(), SectionKind::getReadOnly(), /*C=*/nullptr, diff --git a/llvm/test/CodeGen/X86/jump-table-partition.ll b/llvm/test/CodeGen/X86/jump-table-partition.ll index 3a8f1395f6b283..4022550096fcc4 100644 --- a/llvm/test/CodeGen/X86/jump-table-partition.ll +++ b/llvm/test/CodeGen/X86/jump-table-partition.ll @@ -2,18 +2,22 @@ ; requires: asserts ; RUN: llc -stop-after=block-placement %s -o - | llc --run-pass=static-data-splitter -stats -x mir -o - 2>&1 | FileCheck %s --check-prefix=STAT +; RUN: llc -enable-split-machine-functions -split-static-data --function-sections -data-sections %s -o - 2>&1 | FileCheck %s --check-prefix=SECTION ; `func_with_hot_jumptable` contains a hot jump table and `func_with_cold_jumptable` contains a cold one. ; `func_without_entry_count` simulates the functions without profile information (e.g., not instrumented or not profiled), ; it's jump table hotness is unknown and regarded as hot conservatively. ; ; Tests stat messages are expected. -; TODO: Update test to verify section suffixes when target-lowering and assembler changes are implemented. -; ; STAT-DAG: 1 static-data-splitter - Number of cold jump tables seen ; STAT-DAG: 1 static-data-splitter - Number of hot jump tables seen ; STAT-DAG: 1 static-data-splitter - Number of jump tables with unknown hotness +; TODO: Construct a test case where a hot function has a cold jump table. +; SECTION: .section .rodata.hot.func_with_hot_jumptable +; SECTION: .section .rodata.unlikely.func_with_cold_jumptable +; SECTION: .section .rodata.hot.func_without_entry_count + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits