Skip to content
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

[PowerPC][AIX] Emit PowerPC version for XCOFF #113214

Merged
merged 8 commits into from
Dec 10, 2024

Conversation

amy-kwan
Copy link
Contributor

This PR emits implements the ability to emit the PPC version for both assembly and object files on AIX.

Furthermore, this PR is intended to be a commandeered version of Esme's previous PR: #95510

@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2024

@llvm/pr-subscribers-objectyaml
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-debuginfo

Author: Amy Kwan (amy-kwan)

Changes

This PR emits implements the ability to emit the PPC version for both assembly and object files on AIX.

Furthermore, this PR is intended to be a commandeered version of Esme's previous PR: #95510


Patch is 31.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/113214.diff

31 Files Affected:

  • (modified) llvm/include/llvm/BinaryFormat/XCOFF.h (+28-3)
  • (modified) llvm/include/llvm/MC/MCAssembler.h (+6)
  • (modified) llvm/include/llvm/MC/MCObjectStreamer.h (+1)
  • (modified) llvm/include/llvm/MC/MCObjectWriter.h (+3)
  • (modified) llvm/include/llvm/MC/MCStreamer.h (+3)
  • (modified) llvm/lib/BinaryFormat/XCOFF.cpp (+59)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+23-3)
  • (modified) llvm/lib/MC/MCAsmStreamer.cpp (+9)
  • (modified) llvm/lib/MC/MCObjectStreamer.cpp (+4)
  • (modified) llvm/lib/MC/MCStreamer.cpp (+3)
  • (modified) llvm/lib/MC/XCOFFObjectWriter.cpp (+2-5)
  • (added) llvm/test/CodeGen/PowerPC/aix-cpu-version.ll (+17)
  • (modified) llvm/test/CodeGen/PowerPC/aix-extern-weak.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-extern.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-c.ll (+54-9)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll (+3-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-f.ll (+3-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll (+1-1)
  • (modified) llvm/test/CodeGen/PowerPC/aix-llvm-intrinsic.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-tls-xcoff-variables.ll (+1-1)
  • (modified) llvm/test/CodeGen/PowerPC/aix-weak.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-xcoff-data.ll (+4-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll (+1-2)
  • (modified) llvm/test/DebugInfo/XCOFF/empty.ll (+2)
  • (modified) llvm/test/DebugInfo/XCOFF/explicit-section.ll (+1)
  • (modified) llvm/test/DebugInfo/XCOFF/function-sections.ll (+1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols-invalid.test (+1-1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols.test (+1-1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols64.test (+1-1)
  • (modified) llvm/test/tools/yaml2obj/XCOFF/aux-symbols.yaml (+6-6)
  • (modified) llvm/tools/llvm-readobj/XCOFFDumper.cpp (+6-1)
diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h
index bbcd8a4f29ae91..b48976769c0c47 100644
--- a/llvm/include/llvm/BinaryFormat/XCOFF.h
+++ b/llvm/include/llvm/BinaryFormat/XCOFF.h
@@ -333,10 +333,33 @@ enum CFileLangId : uint8_t {
   TB_CPLUSPLUS = 9 ///< C++ language.
 };
 
+// XCOFF specific CPU IDs, defined in AIX OS header: `/usr/include/aouthdr.h`.
 enum CFileCpuId : uint8_t {
-  TCPU_PPC64 = 2, ///< PowerPC common architecture 64-bit mode.
-  TCPU_COM = 3,   ///< POWER and PowerPC architecture common.
-  TCPU_970 = 19   ///< PPC970 - PowerPC 64-bit architecture.
+  TCPU_INVALID = 0, ///< Invalid id - assumes POWER for old objects.
+  TCPU_PPC = 1,     ///< PowerPC common architecture 32 bit mode.
+  TCPU_PPC64 = 2,   ///< PowerPC common architecture 64-bit mode.
+  TCPU_COM = 3,     ///< POWER and PowerPC architecture common.
+  TCPU_PWR = 4,     ///< POWER common architecture objects.
+  TCPU_ANY = 5,     ///< Mixture of any incompatable POWER
+                    ///< and PowerPC architecture implementations.
+  TCPU_601 = 6,     ///< 601 implementation of PowerPC architecture.
+  TCPU_603 = 7,     ///< 603 implementation of PowerPC architecture.
+  TCPU_604 = 8,     ///< 604 implementation of PowerPC architecture.
+
+  // The following are PowerPC 64-bit architectures.
+  TCPU_620 = 16,
+  TCPU_A35 = 17,
+  TCPU_PWR5 = 18,
+  TCPU_970 = 19,
+  TCPU_PWR6 = 20,
+  TCPU_PWR5X = 22,
+  TCPU_PWR6E = 23,
+  TCPU_PWR7 = 24,
+  TCPU_PWR8 = 25,
+  TCPU_PWR9 = 26,
+  TCPU_PWR10 = 27,
+
+  TCPU_PWRX = 224 ///< RS2 implementation of POWER architecture.
 };
 
 enum SymbolAuxType : uint8_t {
@@ -350,6 +373,7 @@ enum SymbolAuxType : uint8_t {
 
 StringRef getMappingClassString(XCOFF::StorageMappingClass SMC);
 StringRef getRelocationTypeString(XCOFF::RelocationType Type);
+StringRef getTCPUString(XCOFF::CFileCpuId TCPU);
 Expected<SmallString<32>> parseParmsType(uint32_t Value, unsigned FixedParmsNum,
                                          unsigned FloatingParmsNum);
 Expected<SmallString<32>> parseParmsTypeWithVecInfo(uint32_t Value,
@@ -468,6 +492,7 @@ enum ExtendedTBTableFlag : uint8_t {
 
 StringRef getNameForTracebackTableLanguageId(TracebackTable::LanguageID LangId);
 SmallString<32> getExtendedTBTableFlagString(uint8_t Flag);
+XCOFF::CFileCpuId getCpuID(StringRef CPU);
 
 struct CsectProperties {
   CsectProperties(StorageMappingClass SMC, SymbolType ST)
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h
index a68eb49fda2825..e9ed64f36e3a0d 100644
--- a/llvm/include/llvm/MC/MCAssembler.h
+++ b/llvm/include/llvm/MC/MCAssembler.h
@@ -70,6 +70,9 @@ class MCAssembler {
 
   SmallVector<const MCSymbol *, 0> Symbols;
 
+  // PPC CPU type.
+  std::string CPU;
+
   MCDwarfLineTableParams LTParams;
 
   /// The set of function symbols for which a .thumb_func directive has
@@ -225,6 +228,9 @@ class MCAssembler {
     return make_pointee_range(Symbols);
   }
 
+  void setCPU(std::string TargetCPU) { CPU = std::move(TargetCPU); }
+  StringRef getCPU() const { return CPU; }
+
   bool registerSection(MCSection &Section);
   bool registerSymbol(const MCSymbol &Symbol);
 
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index aaa13be6b29868..0b0b3477d03273 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -185,6 +185,7 @@ class MCObjectStreamer : public MCStreamer {
   void emitFileDirective(StringRef Filename) override;
   void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                          StringRef TimeStamp, StringRef Description) override;
+  void emitMachineDirective(StringRef CPU) override;
 
   void emitAddrsig() override;
   void emitAddrsigSym(const MCSymbol *Sym) override;
diff --git a/llvm/include/llvm/MC/MCObjectWriter.h b/llvm/include/llvm/MC/MCObjectWriter.h
index 81ba6ffd5d44e4..2306483dc9e8e3 100644
--- a/llvm/include/llvm/MC/MCObjectWriter.h
+++ b/llvm/include/llvm/MC/MCObjectWriter.h
@@ -36,6 +36,8 @@ class MCObjectWriter {
   SmallVector<std::pair<std::string, size_t>, 0> FileNames;
   // XCOFF specific: Optional compiler version.
   std::string CompilerVersion;
+  // AIX specific: CPU type.
+  std::string CPUType;
   std::vector<const MCSymbol *> AddrsigSyms;
   bool EmitAddrsigSection = false;
   bool SubsectionsViaSymbols = false;
@@ -100,6 +102,7 @@ class MCObjectWriter {
   void setCompilerVersion(StringRef CompilerVers) {
     CompilerVersion = CompilerVers;
   }
+  void setCPU(StringRef TargetCPU) { CPUType = TargetCPU; }
 
   /// Tell the object writer to emit an address-significance table during
   /// writeObject(). If this function is not called, all symbols are treated as
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 707aecc5dc578e..2408cd730b3a2f 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -871,6 +871,9 @@ class MCStreamer {
   virtual void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                                  StringRef TimeStamp, StringRef Description);
 
+  // Emit '.machine "CPU"' assembler directive.
+  virtual void emitMachineDirective(StringRef CPU);
+
   /// Emit the "identifiers" directive.  This implements the
   /// '.ident "version foo"' assembler directive.
   virtual void emitIdent(StringRef IdentString) {}
diff --git a/llvm/lib/BinaryFormat/XCOFF.cpp b/llvm/lib/BinaryFormat/XCOFF.cpp
index 6b11ab2ff96bca..e0a4471bdb9c35 100644
--- a/llvm/lib/BinaryFormat/XCOFF.cpp
+++ b/llvm/lib/BinaryFormat/XCOFF.cpp
@@ -9,8 +9,10 @@
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
+#include "llvm/TargetParser/PPCTargetParser.h"
 
 using namespace llvm;
 
@@ -107,6 +109,63 @@ StringRef XCOFF::getNameForTracebackTableLanguageId(
 }
 #undef LANG_CASE
 
+XCOFF::CFileCpuId XCOFF::getCpuID(StringRef CPUName) {
+  StringRef CPU = PPC::normalizeCPUName(CPUName);
+  return StringSwitch<XCOFF::CFileCpuId>(CPU)
+      .Cases("generic", "COM", XCOFF::TCPU_COM)
+      .Case("601", XCOFF::TCPU_601)
+      .Cases("602", "603", "603e", "603ev", XCOFF::TCPU_603)
+      .Cases("604", "604e", XCOFF::TCPU_604)
+      .Case("620", XCOFF::TCPU_620)
+      .Case("970", XCOFF::TCPU_970)
+      .Cases("a2", "g3", "g4", "g5", "e500", XCOFF::TCPU_COM)
+      .Cases("pwr3", "pwr4", XCOFF::TCPU_COM)
+      .Cases("pwr5", "PWR5", XCOFF::TCPU_PWR5)
+      .Cases("pwr5x", "PWR5X", XCOFF::TCPU_PWR5X)
+      .Cases("pwr6", "PWR6", XCOFF::TCPU_PWR6)
+      .Cases("pwr6x", "PWR6E", XCOFF::TCPU_PWR6E)
+      .Cases("pwr7", "PWR7", XCOFF::TCPU_PWR7)
+      .Cases("pwr8", "PWR8", XCOFF::TCPU_PWR8)
+      .Cases("pwr9", "PWR9", XCOFF::TCPU_PWR9)
+      .Cases("pwr10", "PWR10", XCOFF::TCPU_PWR10)
+      .Cases("ppc", "PPC", "ppc32", "ppc64", XCOFF::TCPU_COM)
+      .Case("ppc64le", XCOFF::TCPU_PWR8)
+      .Case("future", XCOFF::TCPU_PWR10)
+      .Cases("any", "ANY", XCOFF::TCPU_ANY)
+      .Default(XCOFF::TCPU_INVALID);
+}
+
+#define TCPU_CASE(A)                                                           \
+  case XCOFF::TCPU_##A:                                                        \
+    return #A;
+StringRef XCOFF::getTCPUString(XCOFF::CFileCpuId TCPU) {
+  switch (TCPU) {
+    TCPU_CASE(INVALID)
+    TCPU_CASE(PPC)
+    TCPU_CASE(PPC64)
+    TCPU_CASE(COM)
+    TCPU_CASE(PWR)
+    TCPU_CASE(ANY)
+    TCPU_CASE(601)
+    TCPU_CASE(603)
+    TCPU_CASE(604)
+    TCPU_CASE(620)
+    TCPU_CASE(A35)
+    TCPU_CASE(PWR5)
+    TCPU_CASE(970)
+    TCPU_CASE(PWR6)
+    TCPU_CASE(PWR5X)
+    TCPU_CASE(PWR6E)
+    TCPU_CASE(PWR7)
+    TCPU_CASE(PWR8)
+    TCPU_CASE(PWR9)
+    TCPU_CASE(PWR10)
+    TCPU_CASE(PWRX)
+  }
+  return "INVALID";
+}
+#undef TCPU_CASE
+
 Expected<SmallString<32>> XCOFF::parseParmsType(uint32_t Value,
                                                 unsigned FixedParmsNum,
                                                 unsigned FloatingParmsNum) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index bf4c707cca06d5..2b8c7789728b2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -120,6 +120,7 @@
 #include "llvm/Target/TargetLoweringObjectFile.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/TargetParser/PPCTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 #include <algorithm>
 #include <cassert>
@@ -508,9 +509,28 @@ bool AsmPrinter::doInitialization(Module &M) {
     }
   }
 
-  // On AIX, emit bytes for llvm.commandline metadata after .file so that the
-  // C_INFO symbol is preserved if any csect is kept by the linker.
-  if (TM.getTargetTriple().isOSBinFormatXCOFF()) {
+  if (Target.isOSBinFormatXCOFF()) {
+    // Emit .machine directive on AIX.
+    XCOFF::CFileCpuId TargetCpuId = XCOFF::TCPU_INVALID;
+    // Walk through the "target-cpu" attribute of functions and use the newest
+    // level as the CPU of the module.
+    for (auto &F : M) {
+      XCOFF::CFileCpuId FunCpuId =
+          XCOFF::getCpuID(TM.getSubtargetImpl(F)->getCPU());
+      if (FunCpuId > TargetCpuId)
+        TargetCpuId = FunCpuId;
+    }
+    // If there is no "target-cpu" attribute in functions, take the "-mcpu"
+    // value. If both are omitted, use getNormalizedPPCTargetCPU() to determine
+    // the default CPU.
+    if (!TargetCpuId)
+      TargetCpuId = XCOFF::getCpuID(TM.getTargetCPU().empty()
+                                        ? PPC::getNormalizedPPCTargetCPU(Target)
+                                        : TM.getTargetCPU());
+    OutStreamer->emitMachineDirective(XCOFF::getTCPUString(TargetCpuId));
+
+    // On AIX, emit bytes for llvm.commandline metadata after .file so that the
+    // C_INFO symbol is preserved if any csect is kept by the linker.
     emitModuleCommandLines(M);
     // Now we can generate section information.
     OutStreamer->initSections(false, *TM.getMCSubtargetInfo());
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 31b519a3e5c56a..5fb385f1a17a22 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -288,6 +288,9 @@ class MCAsmStreamer final : public MCStreamer {
   void emitFileDirective(StringRef Filename) override;
   void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                          StringRef TimeStamp, StringRef Description) override;
+
+  void emitMachineDirective(StringRef CPU) override;
+
   Expected<unsigned> tryEmitDwarfFileDirective(
       unsigned FileNo, StringRef Directory, StringRef Filename,
       std::optional<MD5::MD5Result> Checksum = std::nullopt,
@@ -1628,6 +1631,12 @@ void MCAsmStreamer::emitFileDirective(StringRef Filename,
   EmitEOL();
 }
 
+void MCAsmStreamer::emitMachineDirective(StringRef CPU) {
+  OS << "\t.machine\t";
+  PrintQuotedString(CPU, OS);
+  EmitEOL();
+}
+
 void MCAsmStreamer::printDwarfFileDirective(
     unsigned FileNo, StringRef Directory, StringRef Filename,
     std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index b2b21435fa4af4..b13967d6860522 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -804,6 +804,10 @@ void MCObjectStreamer::emitFileDirective(StringRef Filename,
   // with the integrated assembler.
 }
 
+void MCObjectStreamer::emitMachineDirective(StringRef CPU) {
+  getAssembler().getWriter().setCPU(CPU);
+}
+
 void MCObjectStreamer::emitAddrsig() {
   getAssembler().getWriter().emitAddrsigSection();
 }
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 13b162768578c5..6b1f3b7e3e11d3 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1174,6 +1174,9 @@ void MCStreamer::emitFileDirective(StringRef Filename,
                                    StringRef CompilerVersion,
                                    StringRef TimeStamp, StringRef Description) {
 }
+void MCStreamer::emitMachineDirective(StringRef CPU) {
+  llvm_unreachable("this directive only supported on XCOFF targets");
+}
 void MCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
   llvm_unreachable("this directive only supported on COFF targets");
 }
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index c7f29c73eaac09..33499f5c70a286 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -1184,11 +1184,8 @@ void XCOFFObjectWriter::writeSymbolTable(MCAssembler &Asm) {
       LangID = XCOFF::TB_Fortran;
     else
       LangID = XCOFF::TB_CPLUSPLUS;
-    uint8_t CpuID;
-    if (is64Bit())
-      CpuID = XCOFF::TCPU_PPC64;
-    else
-      CpuID = XCOFF::TCPU_COM;
+
+    uint8_t CpuID = XCOFF::getCpuID(CPUType);
 
     int NumberOfFileAuxEntries = 1;
     if (!Vers.empty())
diff --git a/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll b/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll
new file mode 100644
index 00000000000000..f9ef6c642b0c1f
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll
@@ -0,0 +1,17 @@
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff  < %s | FileCheck %s
+
+; CHECK:      .file "1.c"
+; CHECK-NEXT: .machine "PWR8"
+; CHECK-NEXT: .csect ..text..[PR],5
+; CHECK-NEXT: .rename ..text..[PR],""
+
+source_filename = "1.c"
+
+define dso_local signext i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, ptr %retval, align 4
+  ret i32 0
+}
+
+attributes #0 = {"target-cpu"="pwr8"}
diff --git a/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll b/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
index 173c58567e40b3..0cca7eab910473 100644
--- a/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
@@ -68,8 +68,7 @@ declare extern_weak void @foo_ext_weak(ptr)
 ; CHECKSYM-NEXT:     Value (SymbolTableIndex): 0x0
 ; CHECKSYM-NEXT:     Section: N_DEBUG
 ; CHECKSYM-NEXT:     Source Language ID: TB_CPLUSPLUS (0x9)
-; CHECKSYM32-NEXT:   CPU Version ID: TCPU_COM (0x3)
-; CHECKSYM64-NEXT:   CPU Version ID: TCPU_PPC64 (0x2)
+; CHECKSYM-NEXT:     CPU Version ID: TCPU_COM (0x3)
 ; CHECKSYM-NEXT:     StorageClass: C_FILE (0x67)
 ; CHECKSYM-NEXT:     NumberOfAuxEntries: 2
 ; CHECKSYM:        Symbol {
diff --git a/llvm/test/CodeGen/PowerPC/aix-extern.ll b/llvm/test/CodeGen/PowerPC/aix-extern.ll
index ff2a803608807c..71b17ad35c70d7 100644
--- a/llvm/test/CodeGen/PowerPC/aix-extern.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-extern.ll
@@ -91,8 +91,7 @@ declare i32 @bar_extern(ptr)
 ; CHECKSYM-NEXT:     Value (SymbolTableIndex): 0x0
 ; CHECKSYM-NEXT:     Section: N_DEBUG
 ; CHECKSYM-NEXT:     Source Language ID: TB_CPLUSPLUS (0x9)
-; CHECKSYM32-NEXT:   CPU Version ID: TCPU_COM (0x3)
-; CHECKSYM64-NEXT:   CPU Version ID: TCPU_PPC64 (0x2)
+; CHECKSYM-NEXT:     CPU Version ID: TCPU_COM (0x3)
 ; CHECKSYM-NEXT:     StorageClass: C_FILE (0x67)
 ; CHECKSYM-NEXT:     NumberOfAuxEntries: 2
 ; CHECKSYM:        Symbol {
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-c.ll b/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
index c4202a0c58cee3..2c6d1941fa992e 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
@@ -1,12 +1,57 @@
-; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
-; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr9  < %s | FileCheck --check-prefixes=ASM %s
+
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr9 -filetype=obj -o %t.o < %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ32 %s
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr9 -filetype=obj -o %t64.o < %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ64 %s
 
 source_filename = "1.c"
 
-; OBJ: Name: .file
-; OBJ: Source Language ID: TB_C (0x0)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
-; OBJ: Name: 1.c
+; ASM:      .file   "1.c",,"LLVM{{.*}}"
+; ASM-NEXT: .machine   "PWR9"
+; ASM-NEXT: .csect ..text..[PR],5
+; ASM-NEXT: .rename	..text..[PR],""
+
+; OBJ32:      Symbol {
+; OBJ32-NEXT:   Index: 0
+; OBJ32-NEXT:   Name: .file
+; OBJ32-NEXT:   Value (SymbolTableIndex): 0x0
+; OBJ32-NEXT:   Section: N_DEBUG
+; OBJ32-NEXT:   Source Language ID: TB_C (0x0)
+; OBJ32-NEXT:   CPU Version ID: TCPU_PWR9 (0x1A)
+; OBJ32-NEXT:   StorageClass: C_FILE (0x67)
+; OBJ32-NEXT:   NumberOfAuxEntries: 2
+; OBJ32-NEXT:   File Auxiliary Entry {
+; OBJ32-NEXT:     Index: 1
+; OBJ32-NEXT:     Name: 1.c
+; OBJ32-NEXT:     Type: XFT_FN (0x0)
+; OBJ32-NEXT:   }
+; OBJ32-NEXT:   File Auxiliary Entry {
+; OBJ32-NEXT:     Index: 2
+; OBJ32-NEXT:     Name: LLVM
+; OBJ32-NEXT:     Type: XFT_CV (0x2)
+; OBJ32-NEXT:   }
+; OBJ32-NEXT: }
+
+; OBJ64:      Symbol {
+; OBJ64-NEXT:   Index: 0
+; OBJ64-NEXT:   Name: .file
+; OBJ64-NEXT:   Value (SymbolTableIndex): 0x0
+; OBJ64-NEXT:   Section: N_DEBUG
+; OBJ64-NEXT:   Source Language ID: TB_C (0x0)
+; OBJ64-NEXT:   CPU Version ID: TCPU_PWR9 (0x1A)
+; OBJ64-NEXT:   StorageClass: C_FILE (0x67)
+; OBJ64-NEXT:   NumberOfAuxEntries: 2
+; OBJ64-NEXT:   File Auxiliary Entry {
+; OBJ64-NEXT:     Index: 1
+; OBJ64-NEXT:     Name: 1.c
+; OBJ64-NEXT:     Type: XFT_FN (0x0)
+; OBJ64-NEXT:     Auxiliary Type: AUX_FILE (0xFC)
+; OBJ64-NEXT:   }
+; OBJ64-NEXT:   File Auxiliary Entry {
+; OBJ64-NEXT:     Index: 2
+; OBJ64-NEXT:     Name: LLVM
+; OBJ64-NEXT:     Type: XFT_CV (0x2)
+; OBJ64-NEXT:     Auxiliary Type: AUX_FILE (0xFC)
+; OBJ64-NEXT:   }
+; OBJ64-NEXT: }
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll b/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
index 802281b6c1eaa4..873619d20cd2c8 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
@@ -1,12 +1,11 @@
 ; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ %s
 ; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ %s
 
 source_filename = "1.cpp"
 
 ; OBJ: Name: .file
 ; OBJ: Source Language ID: TB_CPLUSPLUS (0x9)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
+; OBJ: CPU Version ID: TCPU_PWR7 (0x18)
 ; OBJ: Name: 1.cpp
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-f.ll b/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
index 99036bde702d6e..1167148d21a7fa 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
@@ -1,12 +1,11 @@
 ; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ %s
 ; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ %s
 
 source_filename = "1.f95"
 
 ; OBJ: Name: .file
 ; OBJ: Source Language ID: TB_Fortran (0x1)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
+; OBJ: CPU Version ID: TCPU_PWR7 (0x18)
 ; OBJ: Name: 1.f95
diff --git a/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll b/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
index 4cca1b4d6f7bad..50221acc2b3ad8 100644
--- a/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
@@ -17,7 +17,7 @@ entry:
 ; CHECK-NEXT:     Value (SymbolTab...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2024

@llvm/pr-subscribers-backend-powerpc

Author: Amy Kwan (amy-kwan)

Changes

This PR emits implements the ability to emit the PPC version for both assembly and object files on AIX.

Furthermore, this PR is intended to be a commandeered version of Esme's previous PR: #95510


Patch is 31.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/113214.diff

31 Files Affected:

  • (modified) llvm/include/llvm/BinaryFormat/XCOFF.h (+28-3)
  • (modified) llvm/include/llvm/MC/MCAssembler.h (+6)
  • (modified) llvm/include/llvm/MC/MCObjectStreamer.h (+1)
  • (modified) llvm/include/llvm/MC/MCObjectWriter.h (+3)
  • (modified) llvm/include/llvm/MC/MCStreamer.h (+3)
  • (modified) llvm/lib/BinaryFormat/XCOFF.cpp (+59)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+23-3)
  • (modified) llvm/lib/MC/MCAsmStreamer.cpp (+9)
  • (modified) llvm/lib/MC/MCObjectStreamer.cpp (+4)
  • (modified) llvm/lib/MC/MCStreamer.cpp (+3)
  • (modified) llvm/lib/MC/XCOFFObjectWriter.cpp (+2-5)
  • (added) llvm/test/CodeGen/PowerPC/aix-cpu-version.ll (+17)
  • (modified) llvm/test/CodeGen/PowerPC/aix-extern-weak.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-extern.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-c.ll (+54-9)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll (+3-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-filename-f.ll (+3-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll (+1-1)
  • (modified) llvm/test/CodeGen/PowerPC/aix-llvm-intrinsic.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-tls-xcoff-variables.ll (+1-1)
  • (modified) llvm/test/CodeGen/PowerPC/aix-weak.ll (+1-2)
  • (modified) llvm/test/CodeGen/PowerPC/aix-xcoff-data.ll (+4-4)
  • (modified) llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll (+1-2)
  • (modified) llvm/test/DebugInfo/XCOFF/empty.ll (+2)
  • (modified) llvm/test/DebugInfo/XCOFF/explicit-section.ll (+1)
  • (modified) llvm/test/DebugInfo/XCOFF/function-sections.ll (+1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols-invalid.test (+1-1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols.test (+1-1)
  • (modified) llvm/test/tools/llvm-readobj/XCOFF/symbols64.test (+1-1)
  • (modified) llvm/test/tools/yaml2obj/XCOFF/aux-symbols.yaml (+6-6)
  • (modified) llvm/tools/llvm-readobj/XCOFFDumper.cpp (+6-1)
diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h
index bbcd8a4f29ae91..b48976769c0c47 100644
--- a/llvm/include/llvm/BinaryFormat/XCOFF.h
+++ b/llvm/include/llvm/BinaryFormat/XCOFF.h
@@ -333,10 +333,33 @@ enum CFileLangId : uint8_t {
   TB_CPLUSPLUS = 9 ///< C++ language.
 };
 
+// XCOFF specific CPU IDs, defined in AIX OS header: `/usr/include/aouthdr.h`.
 enum CFileCpuId : uint8_t {
-  TCPU_PPC64 = 2, ///< PowerPC common architecture 64-bit mode.
-  TCPU_COM = 3,   ///< POWER and PowerPC architecture common.
-  TCPU_970 = 19   ///< PPC970 - PowerPC 64-bit architecture.
+  TCPU_INVALID = 0, ///< Invalid id - assumes POWER for old objects.
+  TCPU_PPC = 1,     ///< PowerPC common architecture 32 bit mode.
+  TCPU_PPC64 = 2,   ///< PowerPC common architecture 64-bit mode.
+  TCPU_COM = 3,     ///< POWER and PowerPC architecture common.
+  TCPU_PWR = 4,     ///< POWER common architecture objects.
+  TCPU_ANY = 5,     ///< Mixture of any incompatable POWER
+                    ///< and PowerPC architecture implementations.
+  TCPU_601 = 6,     ///< 601 implementation of PowerPC architecture.
+  TCPU_603 = 7,     ///< 603 implementation of PowerPC architecture.
+  TCPU_604 = 8,     ///< 604 implementation of PowerPC architecture.
+
+  // The following are PowerPC 64-bit architectures.
+  TCPU_620 = 16,
+  TCPU_A35 = 17,
+  TCPU_PWR5 = 18,
+  TCPU_970 = 19,
+  TCPU_PWR6 = 20,
+  TCPU_PWR5X = 22,
+  TCPU_PWR6E = 23,
+  TCPU_PWR7 = 24,
+  TCPU_PWR8 = 25,
+  TCPU_PWR9 = 26,
+  TCPU_PWR10 = 27,
+
+  TCPU_PWRX = 224 ///< RS2 implementation of POWER architecture.
 };
 
 enum SymbolAuxType : uint8_t {
@@ -350,6 +373,7 @@ enum SymbolAuxType : uint8_t {
 
 StringRef getMappingClassString(XCOFF::StorageMappingClass SMC);
 StringRef getRelocationTypeString(XCOFF::RelocationType Type);
+StringRef getTCPUString(XCOFF::CFileCpuId TCPU);
 Expected<SmallString<32>> parseParmsType(uint32_t Value, unsigned FixedParmsNum,
                                          unsigned FloatingParmsNum);
 Expected<SmallString<32>> parseParmsTypeWithVecInfo(uint32_t Value,
@@ -468,6 +492,7 @@ enum ExtendedTBTableFlag : uint8_t {
 
 StringRef getNameForTracebackTableLanguageId(TracebackTable::LanguageID LangId);
 SmallString<32> getExtendedTBTableFlagString(uint8_t Flag);
+XCOFF::CFileCpuId getCpuID(StringRef CPU);
 
 struct CsectProperties {
   CsectProperties(StorageMappingClass SMC, SymbolType ST)
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h
index a68eb49fda2825..e9ed64f36e3a0d 100644
--- a/llvm/include/llvm/MC/MCAssembler.h
+++ b/llvm/include/llvm/MC/MCAssembler.h
@@ -70,6 +70,9 @@ class MCAssembler {
 
   SmallVector<const MCSymbol *, 0> Symbols;
 
+  // PPC CPU type.
+  std::string CPU;
+
   MCDwarfLineTableParams LTParams;
 
   /// The set of function symbols for which a .thumb_func directive has
@@ -225,6 +228,9 @@ class MCAssembler {
     return make_pointee_range(Symbols);
   }
 
+  void setCPU(std::string TargetCPU) { CPU = std::move(TargetCPU); }
+  StringRef getCPU() const { return CPU; }
+
   bool registerSection(MCSection &Section);
   bool registerSymbol(const MCSymbol &Symbol);
 
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index aaa13be6b29868..0b0b3477d03273 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -185,6 +185,7 @@ class MCObjectStreamer : public MCStreamer {
   void emitFileDirective(StringRef Filename) override;
   void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                          StringRef TimeStamp, StringRef Description) override;
+  void emitMachineDirective(StringRef CPU) override;
 
   void emitAddrsig() override;
   void emitAddrsigSym(const MCSymbol *Sym) override;
diff --git a/llvm/include/llvm/MC/MCObjectWriter.h b/llvm/include/llvm/MC/MCObjectWriter.h
index 81ba6ffd5d44e4..2306483dc9e8e3 100644
--- a/llvm/include/llvm/MC/MCObjectWriter.h
+++ b/llvm/include/llvm/MC/MCObjectWriter.h
@@ -36,6 +36,8 @@ class MCObjectWriter {
   SmallVector<std::pair<std::string, size_t>, 0> FileNames;
   // XCOFF specific: Optional compiler version.
   std::string CompilerVersion;
+  // AIX specific: CPU type.
+  std::string CPUType;
   std::vector<const MCSymbol *> AddrsigSyms;
   bool EmitAddrsigSection = false;
   bool SubsectionsViaSymbols = false;
@@ -100,6 +102,7 @@ class MCObjectWriter {
   void setCompilerVersion(StringRef CompilerVers) {
     CompilerVersion = CompilerVers;
   }
+  void setCPU(StringRef TargetCPU) { CPUType = TargetCPU; }
 
   /// Tell the object writer to emit an address-significance table during
   /// writeObject(). If this function is not called, all symbols are treated as
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 707aecc5dc578e..2408cd730b3a2f 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -871,6 +871,9 @@ class MCStreamer {
   virtual void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                                  StringRef TimeStamp, StringRef Description);
 
+  // Emit '.machine "CPU"' assembler directive.
+  virtual void emitMachineDirective(StringRef CPU);
+
   /// Emit the "identifiers" directive.  This implements the
   /// '.ident "version foo"' assembler directive.
   virtual void emitIdent(StringRef IdentString) {}
diff --git a/llvm/lib/BinaryFormat/XCOFF.cpp b/llvm/lib/BinaryFormat/XCOFF.cpp
index 6b11ab2ff96bca..e0a4471bdb9c35 100644
--- a/llvm/lib/BinaryFormat/XCOFF.cpp
+++ b/llvm/lib/BinaryFormat/XCOFF.cpp
@@ -9,8 +9,10 @@
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
+#include "llvm/TargetParser/PPCTargetParser.h"
 
 using namespace llvm;
 
@@ -107,6 +109,63 @@ StringRef XCOFF::getNameForTracebackTableLanguageId(
 }
 #undef LANG_CASE
 
+XCOFF::CFileCpuId XCOFF::getCpuID(StringRef CPUName) {
+  StringRef CPU = PPC::normalizeCPUName(CPUName);
+  return StringSwitch<XCOFF::CFileCpuId>(CPU)
+      .Cases("generic", "COM", XCOFF::TCPU_COM)
+      .Case("601", XCOFF::TCPU_601)
+      .Cases("602", "603", "603e", "603ev", XCOFF::TCPU_603)
+      .Cases("604", "604e", XCOFF::TCPU_604)
+      .Case("620", XCOFF::TCPU_620)
+      .Case("970", XCOFF::TCPU_970)
+      .Cases("a2", "g3", "g4", "g5", "e500", XCOFF::TCPU_COM)
+      .Cases("pwr3", "pwr4", XCOFF::TCPU_COM)
+      .Cases("pwr5", "PWR5", XCOFF::TCPU_PWR5)
+      .Cases("pwr5x", "PWR5X", XCOFF::TCPU_PWR5X)
+      .Cases("pwr6", "PWR6", XCOFF::TCPU_PWR6)
+      .Cases("pwr6x", "PWR6E", XCOFF::TCPU_PWR6E)
+      .Cases("pwr7", "PWR7", XCOFF::TCPU_PWR7)
+      .Cases("pwr8", "PWR8", XCOFF::TCPU_PWR8)
+      .Cases("pwr9", "PWR9", XCOFF::TCPU_PWR9)
+      .Cases("pwr10", "PWR10", XCOFF::TCPU_PWR10)
+      .Cases("ppc", "PPC", "ppc32", "ppc64", XCOFF::TCPU_COM)
+      .Case("ppc64le", XCOFF::TCPU_PWR8)
+      .Case("future", XCOFF::TCPU_PWR10)
+      .Cases("any", "ANY", XCOFF::TCPU_ANY)
+      .Default(XCOFF::TCPU_INVALID);
+}
+
+#define TCPU_CASE(A)                                                           \
+  case XCOFF::TCPU_##A:                                                        \
+    return #A;
+StringRef XCOFF::getTCPUString(XCOFF::CFileCpuId TCPU) {
+  switch (TCPU) {
+    TCPU_CASE(INVALID)
+    TCPU_CASE(PPC)
+    TCPU_CASE(PPC64)
+    TCPU_CASE(COM)
+    TCPU_CASE(PWR)
+    TCPU_CASE(ANY)
+    TCPU_CASE(601)
+    TCPU_CASE(603)
+    TCPU_CASE(604)
+    TCPU_CASE(620)
+    TCPU_CASE(A35)
+    TCPU_CASE(PWR5)
+    TCPU_CASE(970)
+    TCPU_CASE(PWR6)
+    TCPU_CASE(PWR5X)
+    TCPU_CASE(PWR6E)
+    TCPU_CASE(PWR7)
+    TCPU_CASE(PWR8)
+    TCPU_CASE(PWR9)
+    TCPU_CASE(PWR10)
+    TCPU_CASE(PWRX)
+  }
+  return "INVALID";
+}
+#undef TCPU_CASE
+
 Expected<SmallString<32>> XCOFF::parseParmsType(uint32_t Value,
                                                 unsigned FixedParmsNum,
                                                 unsigned FloatingParmsNum) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index bf4c707cca06d5..2b8c7789728b2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -120,6 +120,7 @@
 #include "llvm/Target/TargetLoweringObjectFile.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/TargetParser/PPCTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 #include <algorithm>
 #include <cassert>
@@ -508,9 +509,28 @@ bool AsmPrinter::doInitialization(Module &M) {
     }
   }
 
-  // On AIX, emit bytes for llvm.commandline metadata after .file so that the
-  // C_INFO symbol is preserved if any csect is kept by the linker.
-  if (TM.getTargetTriple().isOSBinFormatXCOFF()) {
+  if (Target.isOSBinFormatXCOFF()) {
+    // Emit .machine directive on AIX.
+    XCOFF::CFileCpuId TargetCpuId = XCOFF::TCPU_INVALID;
+    // Walk through the "target-cpu" attribute of functions and use the newest
+    // level as the CPU of the module.
+    for (auto &F : M) {
+      XCOFF::CFileCpuId FunCpuId =
+          XCOFF::getCpuID(TM.getSubtargetImpl(F)->getCPU());
+      if (FunCpuId > TargetCpuId)
+        TargetCpuId = FunCpuId;
+    }
+    // If there is no "target-cpu" attribute in functions, take the "-mcpu"
+    // value. If both are omitted, use getNormalizedPPCTargetCPU() to determine
+    // the default CPU.
+    if (!TargetCpuId)
+      TargetCpuId = XCOFF::getCpuID(TM.getTargetCPU().empty()
+                                        ? PPC::getNormalizedPPCTargetCPU(Target)
+                                        : TM.getTargetCPU());
+    OutStreamer->emitMachineDirective(XCOFF::getTCPUString(TargetCpuId));
+
+    // On AIX, emit bytes for llvm.commandline metadata after .file so that the
+    // C_INFO symbol is preserved if any csect is kept by the linker.
     emitModuleCommandLines(M);
     // Now we can generate section information.
     OutStreamer->initSections(false, *TM.getMCSubtargetInfo());
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 31b519a3e5c56a..5fb385f1a17a22 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -288,6 +288,9 @@ class MCAsmStreamer final : public MCStreamer {
   void emitFileDirective(StringRef Filename) override;
   void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
                          StringRef TimeStamp, StringRef Description) override;
+
+  void emitMachineDirective(StringRef CPU) override;
+
   Expected<unsigned> tryEmitDwarfFileDirective(
       unsigned FileNo, StringRef Directory, StringRef Filename,
       std::optional<MD5::MD5Result> Checksum = std::nullopt,
@@ -1628,6 +1631,12 @@ void MCAsmStreamer::emitFileDirective(StringRef Filename,
   EmitEOL();
 }
 
+void MCAsmStreamer::emitMachineDirective(StringRef CPU) {
+  OS << "\t.machine\t";
+  PrintQuotedString(CPU, OS);
+  EmitEOL();
+}
+
 void MCAsmStreamer::printDwarfFileDirective(
     unsigned FileNo, StringRef Directory, StringRef Filename,
     std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index b2b21435fa4af4..b13967d6860522 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -804,6 +804,10 @@ void MCObjectStreamer::emitFileDirective(StringRef Filename,
   // with the integrated assembler.
 }
 
+void MCObjectStreamer::emitMachineDirective(StringRef CPU) {
+  getAssembler().getWriter().setCPU(CPU);
+}
+
 void MCObjectStreamer::emitAddrsig() {
   getAssembler().getWriter().emitAddrsigSection();
 }
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 13b162768578c5..6b1f3b7e3e11d3 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1174,6 +1174,9 @@ void MCStreamer::emitFileDirective(StringRef Filename,
                                    StringRef CompilerVersion,
                                    StringRef TimeStamp, StringRef Description) {
 }
+void MCStreamer::emitMachineDirective(StringRef CPU) {
+  llvm_unreachable("this directive only supported on XCOFF targets");
+}
 void MCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
   llvm_unreachable("this directive only supported on COFF targets");
 }
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index c7f29c73eaac09..33499f5c70a286 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -1184,11 +1184,8 @@ void XCOFFObjectWriter::writeSymbolTable(MCAssembler &Asm) {
       LangID = XCOFF::TB_Fortran;
     else
       LangID = XCOFF::TB_CPLUSPLUS;
-    uint8_t CpuID;
-    if (is64Bit())
-      CpuID = XCOFF::TCPU_PPC64;
-    else
-      CpuID = XCOFF::TCPU_COM;
+
+    uint8_t CpuID = XCOFF::getCpuID(CPUType);
 
     int NumberOfFileAuxEntries = 1;
     if (!Vers.empty())
diff --git a/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll b/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll
new file mode 100644
index 00000000000000..f9ef6c642b0c1f
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-cpu-version.ll
@@ -0,0 +1,17 @@
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff  < %s | FileCheck %s
+
+; CHECK:      .file "1.c"
+; CHECK-NEXT: .machine "PWR8"
+; CHECK-NEXT: .csect ..text..[PR],5
+; CHECK-NEXT: .rename ..text..[PR],""
+
+source_filename = "1.c"
+
+define dso_local signext i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, ptr %retval, align 4
+  ret i32 0
+}
+
+attributes #0 = {"target-cpu"="pwr8"}
diff --git a/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll b/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
index 173c58567e40b3..0cca7eab910473 100644
--- a/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
@@ -68,8 +68,7 @@ declare extern_weak void @foo_ext_weak(ptr)
 ; CHECKSYM-NEXT:     Value (SymbolTableIndex): 0x0
 ; CHECKSYM-NEXT:     Section: N_DEBUG
 ; CHECKSYM-NEXT:     Source Language ID: TB_CPLUSPLUS (0x9)
-; CHECKSYM32-NEXT:   CPU Version ID: TCPU_COM (0x3)
-; CHECKSYM64-NEXT:   CPU Version ID: TCPU_PPC64 (0x2)
+; CHECKSYM-NEXT:     CPU Version ID: TCPU_COM (0x3)
 ; CHECKSYM-NEXT:     StorageClass: C_FILE (0x67)
 ; CHECKSYM-NEXT:     NumberOfAuxEntries: 2
 ; CHECKSYM:        Symbol {
diff --git a/llvm/test/CodeGen/PowerPC/aix-extern.ll b/llvm/test/CodeGen/PowerPC/aix-extern.ll
index ff2a803608807c..71b17ad35c70d7 100644
--- a/llvm/test/CodeGen/PowerPC/aix-extern.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-extern.ll
@@ -91,8 +91,7 @@ declare i32 @bar_extern(ptr)
 ; CHECKSYM-NEXT:     Value (SymbolTableIndex): 0x0
 ; CHECKSYM-NEXT:     Section: N_DEBUG
 ; CHECKSYM-NEXT:     Source Language ID: TB_CPLUSPLUS (0x9)
-; CHECKSYM32-NEXT:   CPU Version ID: TCPU_COM (0x3)
-; CHECKSYM64-NEXT:   CPU Version ID: TCPU_PPC64 (0x2)
+; CHECKSYM-NEXT:     CPU Version ID: TCPU_COM (0x3)
 ; CHECKSYM-NEXT:     StorageClass: C_FILE (0x67)
 ; CHECKSYM-NEXT:     NumberOfAuxEntries: 2
 ; CHECKSYM:        Symbol {
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-c.ll b/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
index c4202a0c58cee3..2c6d1941fa992e 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-c.ll
@@ -1,12 +1,57 @@
-; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
-; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr9  < %s | FileCheck --check-prefixes=ASM %s
+
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr9 -filetype=obj -o %t.o < %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ32 %s
+; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr9 -filetype=obj -o %t64.o < %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ64 %s
 
 source_filename = "1.c"
 
-; OBJ: Name: .file
-; OBJ: Source Language ID: TB_C (0x0)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
-; OBJ: Name: 1.c
+; ASM:      .file   "1.c",,"LLVM{{.*}}"
+; ASM-NEXT: .machine   "PWR9"
+; ASM-NEXT: .csect ..text..[PR],5
+; ASM-NEXT: .rename	..text..[PR],""
+
+; OBJ32:      Symbol {
+; OBJ32-NEXT:   Index: 0
+; OBJ32-NEXT:   Name: .file
+; OBJ32-NEXT:   Value (SymbolTableIndex): 0x0
+; OBJ32-NEXT:   Section: N_DEBUG
+; OBJ32-NEXT:   Source Language ID: TB_C (0x0)
+; OBJ32-NEXT:   CPU Version ID: TCPU_PWR9 (0x1A)
+; OBJ32-NEXT:   StorageClass: C_FILE (0x67)
+; OBJ32-NEXT:   NumberOfAuxEntries: 2
+; OBJ32-NEXT:   File Auxiliary Entry {
+; OBJ32-NEXT:     Index: 1
+; OBJ32-NEXT:     Name: 1.c
+; OBJ32-NEXT:     Type: XFT_FN (0x0)
+; OBJ32-NEXT:   }
+; OBJ32-NEXT:   File Auxiliary Entry {
+; OBJ32-NEXT:     Index: 2
+; OBJ32-NEXT:     Name: LLVM
+; OBJ32-NEXT:     Type: XFT_CV (0x2)
+; OBJ32-NEXT:   }
+; OBJ32-NEXT: }
+
+; OBJ64:      Symbol {
+; OBJ64-NEXT:   Index: 0
+; OBJ64-NEXT:   Name: .file
+; OBJ64-NEXT:   Value (SymbolTableIndex): 0x0
+; OBJ64-NEXT:   Section: N_DEBUG
+; OBJ64-NEXT:   Source Language ID: TB_C (0x0)
+; OBJ64-NEXT:   CPU Version ID: TCPU_PWR9 (0x1A)
+; OBJ64-NEXT:   StorageClass: C_FILE (0x67)
+; OBJ64-NEXT:   NumberOfAuxEntries: 2
+; OBJ64-NEXT:   File Auxiliary Entry {
+; OBJ64-NEXT:     Index: 1
+; OBJ64-NEXT:     Name: 1.c
+; OBJ64-NEXT:     Type: XFT_FN (0x0)
+; OBJ64-NEXT:     Auxiliary Type: AUX_FILE (0xFC)
+; OBJ64-NEXT:   }
+; OBJ64-NEXT:   File Auxiliary Entry {
+; OBJ64-NEXT:     Index: 2
+; OBJ64-NEXT:     Name: LLVM
+; OBJ64-NEXT:     Type: XFT_CV (0x2)
+; OBJ64-NEXT:     Auxiliary Type: AUX_FILE (0xFC)
+; OBJ64-NEXT:   }
+; OBJ64-NEXT: }
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll b/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
index 802281b6c1eaa4..873619d20cd2c8 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
@@ -1,12 +1,11 @@
 ; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ %s
 ; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ %s
 
 source_filename = "1.cpp"
 
 ; OBJ: Name: .file
 ; OBJ: Source Language ID: TB_CPLUSPLUS (0x9)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
+; OBJ: CPU Version ID: TCPU_PWR7 (0x18)
 ; OBJ: Name: 1.cpp
diff --git a/llvm/test/CodeGen/PowerPC/aix-filename-f.ll b/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
index 99036bde702d6e..1167148d21a7fa 100644
--- a/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-filename-f.ll
@@ -1,12 +1,11 @@
 ; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
-; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ,OBJ32 %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefixes=OBJ %s
 ; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -filetype=obj -o %t64.o < %s
-; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ,OBJ64 %s
+; RUN: llvm-readobj --symbols %t64.o | FileCheck --check-prefixes=OBJ %s
 
 source_filename = "1.f95"
 
 ; OBJ: Name: .file
 ; OBJ: Source Language ID: TB_Fortran (0x1)
-; OBJ32: CPU Version ID: TCPU_COM (0x3)
-; OBJ64: CPU Version ID: TCPU_PPC64 (0x2)
+; OBJ: CPU Version ID: TCPU_PWR7 (0x18)
 ; OBJ: Name: 1.f95
diff --git a/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll b/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
index 4cca1b4d6f7bad..50221acc2b3ad8 100644
--- a/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-func-dsc-gen.ll
@@ -17,7 +17,7 @@ entry:
 ; CHECK-NEXT:     Value (SymbolTab...
[truncated]

@redstar
Copy link
Member

redstar commented Oct 21, 2024

There is already a PPCTargetXCOFFStreamer::emitMachine() method. Why can't this be used to emit the directive? It feels like the code is duplicating existing functionality.

E.g. the code in AsmPrinter::doInitialization() to emit the directive could move to PPCAsmPrinter::emitStartOfAsmFile(), because it is XCOFF+PowerPC specific. Then you have access to the PPCTargetStreamer to call emitMachine(). This avoids adding more XCOFF-specific functions to the global classes.

@amy-kwan amy-kwan force-pushed the amy-kwan/ppc_version branch from a499cd6 to 2ba3f0a Compare November 11, 2024 04:46
Copy link

github-actions bot commented Nov 11, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@amy-kwan
Copy link
Contributor Author

There is already a PPCTargetXCOFFStreamer::emitMachine() method. Why can't this be used to emit the directive? It feels like the code is duplicating existing functionality.

E.g. the code in AsmPrinter::doInitialization() to emit the directive could move to PPCAsmPrinter::emitStartOfAsmFile(), because it is XCOFF+PowerPC specific. Then you have access to the PPCTargetStreamer to call emitMachine(). This avoids adding more XCOFF-specific functions to the global classes.

Unless I am missing something, I do not see why I cannot use the emitMachine() that already exists in PPCTargetXCOFFStreamer. I have updated the patch to leverage this, so thanks for the suggestion @redstar!

The only obvious difference I can see is that the .machine pseudo-op is no longer emitted directly after the .file pseudo-op in my implementation of changing it to use PPCTargetXCOFFStreamer, but unless I am reading the documentation (such as https://www.ibm.com/docs/en/aix/7.3?topic=ops-machine-pseudo-op) incorrectly, I believe this OK.

@amy-kwan
Copy link
Contributor Author

Ping.

Comment on lines 39 to 40
// AIX specific: CPU type.
std::string CPUType;
Copy link
Member

Choose a reason for hiding this comment

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

This (and the setter below) can be moved to the XCOFFObjectWriter, since this is the only user.

Comment on lines 231 to 232
void setCPU(std::string TargetCPU) { CPU = std::move(TargetCPU); }
StringRef getCPU() const { return CPU; }

Copy link
Member

Choose a reason for hiding this comment

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

Is this used anywhere? The CPU is emitted via the PPCTargetStreamer, so I think there is no use for it here.

@@ -100,6 +102,7 @@ class MCObjectWriter {
void setCompilerVersion(StringRef CompilerVers) {
CompilerVersion = CompilerVers;
}
void setCPU(StringRef TargetCPU) { CPUType = TargetCPU; }
Copy link
Member

Choose a reason for hiding this comment

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

Like above.

Comment on lines 430 to 431
MCXCOFFStreamer &XCOFFStreamer = static_cast<MCXCOFFStreamer &>(Streamer);
XCOFFStreamer.getAssembler().getWriter().setCPU(CPU);
Copy link
Member

Choose a reason for hiding this comment

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

With the other changes this would become:

Suggested change
MCXCOFFStreamer &XCOFFStreamer = static_cast<MCXCOFFStreamer &>(Streamer);
XCOFFStreamer.getAssembler().getWriter().setCPU(CPU);
static_cast<XCOFFObjectWriter>(Streamer.getAssembler().getWriter()).setCPU(CPU);

This PR emits implements the ability to emit the PPC version for both assembly
and object files on AIX.

Furthermore, this PR is intended to be a commandeered version of Esme's previous PR:
llvm#95510
@amy-kwan amy-kwan force-pushed the amy-kwan/ppc_version branch from 1f20a2f to 7e696cf Compare December 5, 2024 04:40
@amy-kwan amy-kwan requested a review from redstar December 5, 2024 04:41
Copy link
Member

@redstar redstar left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

XCOFF::CFileCpuId FunCpuId =
XCOFF::getCpuID(TM.getSubtargetImpl(F)->getCPU());
if (FunCpuId > TargetCpuId)
TargetCpuId = FunCpuId;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need a test case for the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think llvm/test/CodeGen/PowerPC/aix-cpu-version.ll is supposed to cover this. Or am I misunderstanding your comment?

Copy link
Contributor

@diggerlin diggerlin Dec 6, 2024

Choose a reason for hiding this comment

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

my suggestion is that two functions with different "target-cpu" value since there is for loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@amy-kwan amy-kwan requested a review from diggerlin December 5, 2024 20:07
@amy-kwan amy-kwan merged commit f31099c into llvm:main Dec 10, 2024
8 checks passed
broxigarchen pushed a commit to broxigarchen/llvm-project that referenced this pull request Dec 10, 2024
This PR emits implements the ability to emit the PPC version for both
assembly and object files on AIX.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants