Skip to content

Commit

Permalink
[PowerPC][AIX] Emit PowerPC version for XCOFF (#113214)
Browse files Browse the repository at this point in the history
This PR emits implements the ability to emit the PPC version for both
assembly and object files on AIX.
  • Loading branch information
amy-kwan authored Dec 10, 2024
1 parent f28e522 commit f31099c
Show file tree
Hide file tree
Showing 27 changed files with 265 additions and 53 deletions.
31 changes: 28 additions & 3 deletions llvm/include/llvm/BinaryFormat/XCOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCXCOFFObjectWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@ class MCXCOFFObjectTargetWriter : public MCObjectTargetWriter {
};

class XCOFFObjectWriter : public MCObjectWriter {
// AIX specific CPU type.
std::string CPUType;

public:
virtual void addExceptionEntry(const MCSymbol *Symbol, const MCSymbol *Trap,
unsigned LanguageCode, unsigned ReasonCode,
unsigned FunctionSize, bool hasDebug) = 0;
virtual void addCInfoSymEntry(StringRef Name, StringRef Metadata) = 0;
StringRef getCPUType() const { return CPUType; }
void setCPU(StringRef TargetCPU) { CPUType = TargetCPU; }
};

std::unique_ptr<MCObjectWriter>
Expand Down
59 changes: 59 additions & 0 deletions llvm/lib/BinaryFormat/XCOFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 2 additions & 5 deletions llvm/lib/MC/XCOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1180,11 +1180,8 @@ void XCOFFWriter::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(getCPUType());

int NumberOfFileAuxEntries = 1;
if (!Vers.empty())
Expand Down
10 changes: 8 additions & 2 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/MC/MCSymbolXCOFF.h"
#include "llvm/MC/MCXCOFFObjectWriter.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -258,7 +259,11 @@ class PPCTargetAsmStreamer : public PPCTargetStreamer {
}

void emitMachine(StringRef CPU) override {
OS << "\t.machine " << CPU << '\n';
const Triple &TT = Streamer.getContext().getTargetTriple();
if (TT.isOSBinFormatXCOFF())
OS << "\t.machine\t" << '\"' << CPU << '\"' << '\n';
else
OS << "\t.machine " << CPU << '\n';
}

void emitAbiVersion(int AbiVersion) override {
Expand Down Expand Up @@ -422,7 +427,8 @@ class PPCTargetXCOFFStreamer : public PPCTargetStreamer {
}

void emitMachine(StringRef CPU) override {
llvm_unreachable("Machine pseudo-ops are invalid for XCOFF.");
static_cast<XCOFFObjectWriter &>(Streamer.getAssemblerPtr()->getWriter())
.setCPU(CPU);
}

void emitAbiVersion(int AbiVersion) override {
Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/TargetParser/PPCTargetParser.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <cassert>
Expand Down Expand Up @@ -3046,6 +3047,30 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
bool PPCAIXAsmPrinter::doInitialization(Module &M) {
const bool Result = PPCAsmPrinter::doInitialization(M);

// Emit the .machine directive on AIX.
const Triple &Target = TM.getTargetTriple();
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 within the functions, take the
// "-mcpu" value. If both are omitted, use getNormalizedPPCTargetCPU() to
// determine the default CPU.
if (!TargetCpuId) {
StringRef TargetCPU = TM.getTargetCPU();
TargetCpuId = XCOFF::getCpuID(
TargetCPU.empty() ? PPC::getNormalizedPPCTargetCPU(Target) : TargetCPU);
}

PPCTargetStreamer *TS =
static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
TS->emitMachine(XCOFF::getTCPUString(TargetCpuId));

auto setCsectAlignment = [this](const GlobalObject *GO) {
// Declarations have 0 alignment which is set by default.
if (GO->isDeclarationForLinker())
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/CodeGen/PowerPC/aix-cpu-version-multifunction.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s

; For the .machine directive emitted on AIX, the "target-cpu" attribute that is
; the newest will be used as the CPU for the module (in this case, PWR10).

; CHECK: .file "file.c"
; CHECK-NEXT: .csect ..text..[PR],5
; CHECK-NEXT: .rename ..text..[PR],""
; CHECK-NEXT: .machine "PWR10"
; CHECK-NOT: .machine "PWR8"

source_filename = "file.c"

define dso_local signext i32 @testFunc1() #0 {
entry:
%retval = alloca i32, align 4
store i32 0, ptr %retval, align 4
ret i32 0
}

define dso_local signext i32 @testFunc2() #1 {
entry:
%retval = alloca i32, align 4
store i32 0, ptr %retval, align 4
ret i32 0
}

attributes #0 = { "target-cpu" = "pwr8" }
attributes #1 = { "target-cpu" = "pwr10" }

17 changes: 17 additions & 0 deletions llvm/test/CodeGen/PowerPC/aix-cpu-version.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s

; CHECK: .file "1.c"
; CHECK-NEXT: .csect ..text..[PR],5
; CHECK-NEXT: .rename ..text..[PR],""
; CHECK-NEXT: .machine "PWR8"

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"}
3 changes: 1 addition & 2 deletions llvm/test/CodeGen/PowerPC/aix-extern-weak.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 1 addition & 2 deletions llvm/test/CodeGen/PowerPC/aix-extern.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
63 changes: 54 additions & 9 deletions llvm/test/CodeGen/PowerPC/aix-filename-c.ll
Original file line number Diff line number Diff line change
@@ -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: .csect ..text..[PR],5
; ASM-NEXT: .rename ..text..[PR],""
; ASM-NEXT: .machine "PWR9"

; 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: }
7 changes: 3 additions & 4 deletions llvm/test/CodeGen/PowerPC/aix-filename-cpp.ll
Original file line number Diff line number Diff line change
@@ -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
7 changes: 3 additions & 4 deletions llvm/test/CodeGen/PowerPC/aix-filename-f.ll
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit f31099c

Please sign in to comment.