[llvm] 0f85393 - [MachO] Port call graph profile section and directive

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 12 06:22:47 PST 2022


Author: Leonard Grey
Date: 2022-01-12T09:22:26-05:00
New Revision: 0f853930042f11f5ee489bd56b48a227d057c37e

URL: https://github.com/llvm/llvm-project/commit/0f853930042f11f5ee489bd56b48a227d057c37e
DIFF: https://github.com/llvm/llvm-project/commit/0f853930042f11f5ee489bd56b48a227d057c37e.diff

LOG: [MachO] Port call graph profile section and directive

This ports the `.cg_profile` assembly directive and call graph profile section
generation to MachO from COFF/ELF. Due to MachO section naming rules, the
section is called `__LLVM,__cg_profile` rather than `.llvm.call-graph-profile`
as in COFF/ELF. Support for llvm-readobj is included to facilitate testing.

Corresponding LLD change is D112164

Differential Revision: https://reviews.llvm.org/D112160

Added: 
    llvm/test/MC/MachO/cgprofile.ll
    llvm/test/MC/MachO/cgprofile.s

Modified: 
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/MC/MCMachOStreamer.cpp
    llvm/lib/MC/MCParser/DarwinAsmParser.cpp
    llvm/lib/MC/MachObjectWriter.cpp
    llvm/tools/llvm-readobj/MachODumper.cpp
    llvm/tools/llvm-readobj/llvm-readobj.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 20ef01e10c20..ce350034d073 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -1188,6 +1188,7 @@ void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer,
   StringRef SectionVal;
 
   GetObjCImageInfo(M, VersionVal, ImageInfoFlags, SectionVal);
+  emitCGProfileMetadata(Streamer, M);
 
   // The section is mandatory. If we don't have it, then we don't have GC info.
   if (SectionVal.empty())

diff  --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp
index 3edf7a3f49e6..88aeeb980738 100644
--- a/llvm/lib/MC/MCMachOStreamer.cpp
+++ b/llvm/lib/MC/MCMachOStreamer.cpp
@@ -116,8 +116,16 @@ class MCMachOStreamer : public MCObjectStreamer {
   void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override {
     getAssembler().getLOHContainer().addDirective(Kind, Args);
   }
+  void emitCGProfileEntry(const MCSymbolRefExpr *From,
+                          const MCSymbolRefExpr *To, uint64_t Count) override {
+    if (!From->getSymbol().isTemporary() && !To->getSymbol().isTemporary())
+      getAssembler().CGProfile.push_back({From, To, Count});
+  }
 
   void finishImpl() override;
+
+  void finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE);
+  void finalizeCGProfile();
 };
 
 } // end anonymous namespace.
@@ -145,7 +153,8 @@ static bool canGoAfterDWARF(const MCSectionMachO &MSec) {
   if (SegName == "__DATA" && (SecName == "__nl_symbol_ptr" ||
                               SecName == "__thread_ptr"))
     return true;
-
+  if (SegName == "__LLVM" && SecName == "__cg_profile")
+    return true;
   return false;
 }
 
@@ -513,9 +522,40 @@ void MCMachOStreamer::finishImpl() {
     }
   }
 
+  finalizeCGProfile();
+
   this->MCObjectStreamer::finishImpl();
 }
 
+void MCMachOStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
+  const MCSymbol *S = &SRE->getSymbol();
+  bool Created;
+  getAssembler().registerSymbol(*S, &Created);
+  if (Created)
+    S->setExternal(true);
+}
+
+void MCMachOStreamer::finalizeCGProfile() {
+  MCAssembler &Asm = getAssembler();
+  if (Asm.CGProfile.empty())
+    return;
+  for (MCAssembler::CGProfileEntry &E : Asm.CGProfile) {
+    finalizeCGProfileEntry(E.From);
+    finalizeCGProfileEntry(E.To);
+  }
+  // We can't write the section out until symbol indices are finalized which
+  // doesn't happen until after section layout. We need to create the section
+  // and set its size now so that it's accounted for in layout.
+  MCSection *CGProfileSection = Asm.getContext().getMachOSection(
+      "__LLVM", "__cg_profile", 0, SectionKind::getMetadata());
+  Asm.registerSection(*CGProfileSection);
+  auto *Frag = new MCDataFragment(CGProfileSection);
+  // For each entry, reserve space for 2 32-bit indices and a 64-bit count.
+  size_t SectionBytes =
+      Asm.CGProfile.size() * (2 * sizeof(uint32_t) + sizeof(uint64_t));
+  Frag->getContents().resize(SectionBytes);
+}
+
 MCStreamer *llvm::createMachOStreamer(MCContext &Context,
                                       std::unique_ptr<MCAsmBackend> &&MAB,
                                       std::unique_ptr<MCObjectWriter> &&OW,

diff  --git a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp
index 3bc13012c019..91aa2de92627 100644
--- a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp
@@ -195,6 +195,8 @@ class DarwinAsmParser : public MCAsmParserExtension {
     addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>(
       ".macosx_version_min");
     addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version");
+    addDirectiveHandler<&DarwinAsmParser::parseDirectiveCGProfile>(
+        ".cg_profile");
 
     LastVersionDirective = SMLoc();
   }
@@ -467,6 +469,7 @@ class DarwinAsmParser : public MCAsmParserExtension {
   bool parseSDKVersion(VersionTuple &SDKVersion);
   void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc,
                     Triple::OSType ExpectedOS);
+  bool parseDirectiveCGProfile(StringRef Directive, SMLoc Loc);
 };
 
 } // end anonymous namespace
@@ -1198,6 +1201,11 @@ bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) {
   return false;
 }
 
+/// parseDirectiveCGProfile
+///   ::= .cg_profile from, to, count
+bool DarwinAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) {
+  return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc);
+}
 
 namespace llvm {
 

diff  --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp
index 16941b1cb727..5105c5d8164d 100644
--- a/llvm/lib/MC/MachObjectWriter.cpp
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -759,6 +759,23 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm,
   computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
                      UndefinedSymbolData);
 
+  if (!Asm.CGProfile.empty()) {
+    MCSection *CGProfileSection = Asm.getContext().getMachOSection(
+        "__LLVM", "__cg_profile", 0, SectionKind::getMetadata());
+    MCDataFragment *Frag = dyn_cast_or_null<MCDataFragment>(
+        &*CGProfileSection->getFragmentList().begin());
+    assert(Frag && "call graph profile section not reserved");
+    Frag->getContents().set_size(0);
+    raw_svector_ostream OS(Frag->getContents());
+    for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) {
+      uint32_t FromIndex = CGPE.From->getSymbol().getIndex();
+      uint32_t ToIndex = CGPE.To->getSymbol().getIndex();
+      support::endian::write(OS, FromIndex, W.Endian);
+      support::endian::write(OS, ToIndex, W.Endian);
+      support::endian::write(OS, CGPE.Count, W.Endian);
+    }
+  }
+
   unsigned NumSections = Asm.size();
   const MCAssembler::VersionInfoType &VersionInfo =
     Layout.getAssembler().getVersionInfo();

diff  --git a/llvm/test/MC/MachO/cgprofile.ll b/llvm/test/MC/MachO/cgprofile.ll
new file mode 100644
index 000000000000..aa8564bd54a7
--- /dev/null
+++ b/llvm/test/MC/MachO/cgprofile.ll
@@ -0,0 +1,51 @@
+; RUN: llc -filetype=asm %s -o - -mtriple x86_64-apple-darwin | FileCheck %s
+; RUN: llc -filetype=obj %s -o %t -mtriple x86_64-apple-darwin
+; RUN: llvm-readobj --cg-profile %t | FileCheck %s --check-prefix=OBJ
+
+declare void @b()
+
+define void @a() {
+  call void @b()
+  ret void
+}
+
+define void @freq(i1 %cond) {
+  br i1 %cond, label %A, label %B
+A:
+  call void @a();
+  ret void
+B:
+  call void @b();
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 5, !"CG Profile", !1}
+!1 = !{!2, !3, !4, !5}
+!2 = !{void ()* @a, void ()* @b, i64 32}
+!3 = !{void (i1)* @freq, void ()* @a, i64 11}
+!4 = !{void (i1)* @freq, void ()* @b, i64 20}
+!5 = !{void (i1)* @freq, null, i64 20}
+
+; CHECK: .cg_profile _a, _b, 32
+; CHECK: .cg_profile _freq, _a, 11
+; CHECK: .cg_profile _freq, _b, 20
+
+; OBJ: CGProfile [
+; OBJ:  CGProfileEntry {
+; OBJ:    From: _a
+; OBJ:    To: _b
+; OBJ:    Weight: 32
+; OBJ:  }
+; OBJ:  CGProfileEntry {
+; OBJ:    From: _freq
+; OBJ:    To: _a
+; OBJ:    Weight: 11
+; OBJ:  }
+; OBJ:  CGProfileEntry {
+; OBJ:    From: _freq
+; OBJ:    To: _b
+; OBJ:    Weight: 20
+; OBJ:  }
+; OBJ:]

diff  --git a/llvm/test/MC/MachO/cgprofile.s b/llvm/test/MC/MachO/cgprofile.s
new file mode 100644
index 000000000000..6d356b3103cb
--- /dev/null
+++ b/llvm/test/MC/MachO/cgprofile.s
@@ -0,0 +1,45 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t
+# RUN: llvm-readobj -S --symbols --sd --cg-profile %t | FileCheck %s
+
+  .section __TEXT,__text
+a:
+
+  .cg_profile a, b, 32
+  .cg_profile freq, a, 11
+  .cg_profile late, late2, 20
+  .cg_profile L.local, b, 42
+
+	.globl late
+late:
+late2: .word 0
+late3:
+L.local:
+
+
+# CHECK:      Name: __cg_profile
+# CHECK-NEXT: Segment: __LLVM
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Size: 0x30
+# CHECK:      SectionData (
+# CHECK-NEXT:   0000: 00000000 04000000 20000000 00000000
+# CHECK-NEXT:   0010: 05000000 00000000 0B000000 00000000
+# CHECK-NEXT:   0020: 03000000 01000000 14000000 00000000
+# CHECK-NEXT: )
+
+# CHECK:        CGProfile [
+# CHECK-NEXT:   CGProfileEntry {
+# CHECK-NEXT:     From: a (0)
+# CHECK-NEXT:     To: b (4)
+# CHECK-NEXT:     Weight: 32
+# CHECK-NEXT:   }
+# CHECK-NEXT:   CGProfileEntry {
+# CHECK-NEXT:     From: freq (5)
+# CHECK-NEXT:     To: a (0)
+# CHECK-NEXT:     Weight: 11
+# CHECK-NEXT:   }
+# CHECK-NEXT:   CGProfileEntry {
+# CHECK-NEXT:     From: late (3)
+# CHECK-NEXT:     To: late2 (1)
+# CHECK-NEXT:     Weight: 20
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]

diff  --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp
index 945b16b8db86..599b0355917e 100644
--- a/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -16,6 +16,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Object/MachO.h"
+#include "llvm/Support/BinaryStreamReader.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ScopedPrinter.h"
 
@@ -34,6 +35,7 @@ class MachODumper : public ObjDumper {
   void printRelocations() override;
   void printUnwindInfo() override;
   void printStackMap() const override;
+  void printCGProfile() override;
 
   void printNeededLibraries() override;
 
@@ -49,6 +51,8 @@ class MachODumper : public ObjDumper {
   template<class MachHeader>
   void printFileHeaders(const MachHeader &Header);
 
+  StringRef getSymbolName(const SymbolRef &Symbol);
+
   void printSymbols() override;
   void printDynamicSymbols() override;
   void printSymbol(const SymbolRef &Symbol);
@@ -551,10 +555,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,
   if (IsExtern) {
     symbol_iterator Symbol = Reloc.getSymbol();
     if (Symbol != Obj->symbol_end()) {
-      Expected<StringRef> TargetNameOrErr = Symbol->getName();
-      if (!TargetNameOrErr)
-        reportError(TargetNameOrErr.takeError(), Obj->getFileName());
-      TargetName = *TargetNameOrErr;
+      TargetName = getSymbolName(*Symbol);
     }
   } else if (!IsScattered) {
     section_iterator SecI = Obj->getRelocationSection(DR);
@@ -601,6 +602,14 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,
   }
 }
 
+StringRef MachODumper::getSymbolName(const SymbolRef &Symbol) {
+  Expected<StringRef> SymbolNameOrErr = Symbol.getName();
+  if (!SymbolNameOrErr) {
+    reportError(SymbolNameOrErr.takeError(), Obj->getFileName());
+  }
+  return *SymbolNameOrErr;
+}
+
 void MachODumper::printSymbols() {
   ListScope Group(W, "Symbols");
 
@@ -614,13 +623,7 @@ void MachODumper::printDynamicSymbols() {
 }
 
 void MachODumper::printSymbol(const SymbolRef &Symbol) {
-  StringRef SymbolName;
-  Expected<StringRef> SymbolNameOrErr = Symbol.getName();
-  if (!SymbolNameOrErr) {
-    // TODO: Actually report errors helpfully.
-    consumeError(SymbolNameOrErr.takeError());
-  } else
-    SymbolName = *SymbolNameOrErr;
+  StringRef SymbolName = getSymbolName(Symbol);
 
   MachOSymbol MOSymbol;
   getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol);
@@ -696,6 +699,48 @@ void MachODumper::printStackMap() const {
         W, StackMapParser<support::big>(StackMapContentsArray));
 }
 
+void MachODumper::printCGProfile() {
+  object::SectionRef CGProfileSection;
+  for (auto Sec : Obj->sections()) {
+    StringRef Name;
+    if (Expected<StringRef> NameOrErr = Sec.getName())
+      Name = *NameOrErr;
+    else
+      consumeError(NameOrErr.takeError());
+
+    if (Name == "__cg_profile") {
+      CGProfileSection = Sec;
+      break;
+    }
+  }
+  if (CGProfileSection == object::SectionRef())
+    return;
+
+  StringRef CGProfileContents =
+      unwrapOrError(Obj->getFileName(), CGProfileSection.getContents());
+  BinaryStreamReader Reader(CGProfileContents, Obj->isLittleEndian()
+                                                   ? llvm::support::little
+                                                   : llvm::support::big);
+
+  ListScope L(W, "CGProfile");
+  while (!Reader.empty()) {
+    uint32_t FromIndex, ToIndex;
+    uint64_t Count;
+    if (Error Err = Reader.readInteger(FromIndex))
+      reportError(std::move(Err), Obj->getFileName());
+    if (Error Err = Reader.readInteger(ToIndex))
+      reportError(std::move(Err), Obj->getFileName());
+    if (Error Err = Reader.readInteger(Count))
+      reportError(std::move(Err), Obj->getFileName());
+    DictScope D(W, "CGProfileEntry");
+    W.printNumber("From", getSymbolName(*Obj->getSymbolByIndex(FromIndex)),
+                  FromIndex);
+    W.printNumber("To", getSymbolName(*Obj->getSymbolByIndex(ToIndex)),
+                  ToIndex);
+    W.printNumber("Weight", Count);
+  }
+}
+
 void MachODumper::printNeededLibraries() {
   ListScope D(W, "NeededLibraries");
 

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index eea486abe0a1..543b0de82cdf 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -448,6 +448,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
       Dumper->printMachOVersionMin();
     if (opts::MachODysymtab)
       Dumper->printMachODysymtab();
+    if (opts::CGProfile)
+      Dumper->printCGProfile();
   }
   if (opts::PrintStackMap)
     Dumper->printStackMap();


        


More information about the llvm-commits mailing list