[SystemZ][z/OS] Add the PPA1 to SystemZAsmPrinter

Differential Revision: https://reviews.llvm.org/D125725
This commit is contained in:
Yusra Syeda 2022-05-18 13:05:11 -04:00
parent 4d8268fbf4
commit 5ac411aea8
10 changed files with 333 additions and 13 deletions

View File

@ -0,0 +1,31 @@
//===-- llvm/BinaryFormat/GOFF.h - GOFF definitions --------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This header contains common, non-processor-specific data structures and
// constants for the GOFF file format.
//
// GOFF specifics can be found in MVS Program Management: Advanced Facilities
//===----------------------------------------------------------------------===//
#ifndef LLVM_BINARYFORMAT_GOFF_H
#define LLVM_BINARYFORMAT_GOFF_H
namespace llvm {
namespace GOFF {
// \brief Subsections of the primary C_CODE section in the object file.
enum SubsectionKind : uint8_t {
SK_PPA1 = 2,
};
} // end namespace GOFF
} // end namespace llvm
#endif // LLVM_BINARYFORMAT_GOFF_H

View File

@ -613,7 +613,8 @@ public:
unsigned Flags,
unsigned EntrySize);
MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind);
MCSectionGOFF *getGOFFSection(StringRef Section, SectionKind Kind,
MCSection *Parent, const MCExpr *SubsectionId);
MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
SectionKind Kind, StringRef COMDATSymName,

View File

@ -225,6 +225,9 @@ protected:
MCSection *GIATsSection = nullptr;
MCSection *GLJMPSection = nullptr;
// GOFF specific sections.
MCSection *PPA1Section = nullptr;
// XCOFF specific sections
MCSection *TOCBaseSection = nullptr;
MCSection *ReadOnly8Section = nullptr;
@ -423,6 +426,9 @@ public:
MCSection *getGIATsSection() const { return GIATsSection; }
MCSection *getGLJMPSection() const { return GLJMPSection; }
// GOFF specific sections.
MCSection *getPPA1Section() const { return PPA1Section; }
// XCOFF specific sections
MCSection *getTOCBaseSection() const { return TOCBaseSection; }

View File

@ -15,6 +15,7 @@
#ifndef LLVM_MC_MCSECTIONGOFF_H
#define LLVM_MC_MCSECTIONGOFF_H
#include "llvm/BinaryFormat/GOFF.h"
#include "llvm/MC/MCSection.h"
#include "llvm/Support/raw_ostream.h"
@ -24,9 +25,12 @@ class MCExpr;
class MCSectionGOFF final : public MCSection {
private:
MCSection *Parent;
const MCExpr *SubsectionId;
friend class MCContext;
MCSectionGOFF(StringRef Name, SectionKind K)
: MCSection(SV_GOFF, Name, K, nullptr) {}
MCSectionGOFF(StringRef Name, SectionKind K, MCSection *P, const MCExpr *Sub)
: MCSection(SV_GOFF, Name, K, nullptr), Parent(P), SubsectionId(Sub) {}
public:
void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
@ -39,6 +43,9 @@ public:
bool isVirtualSection() const override { return false; }
MCSection *getParent() const { return Parent; }
const MCExpr *getSubsectionId() const { return SubsectionId; }
static bool classof(const MCSection *S) { return S->getVariant() == SV_GOFF; }
};
} // end namespace llvm

View File

@ -2593,8 +2593,8 @@ MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
auto *Symbol = TM.getSymbol(GO);
if (Kind.isBSS())
return getContext().getGOFFSection(Symbol->getName(),
SectionKind::getBSS());
return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(),
nullptr, nullptr);
return getContext().getObjectFileInfo()->getTextSection();
}

View File

@ -634,11 +634,14 @@ Optional<unsigned> MCContext::getELFUniqueIDForEntsize(StringRef SectionName,
return (I != ELFEntrySizeMap.end()) ? Optional<unsigned>(I->second) : None;
}
MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind) {
MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind,
MCSection *Parent,
const MCExpr *SubsectionId) {
// Do the lookup. If we don't have a hit, return a new section.
auto &GOFFSection = GOFFUniquingMap[Section.str()];
if (!GOFFSection)
GOFFSection = new (GOFFAllocator.Allocate()) MCSectionGOFF(Section, Kind);
GOFFSection = new (GOFFAllocator.Allocate())
MCSectionGOFF(Section, Kind, Parent, SubsectionId);
return GOFFSection;
}

View File

@ -523,8 +523,13 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
}
void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
TextSection = Ctx->getGOFFSection(".text", SectionKind::getText());
BSSSection = Ctx->getGOFFSection(".bss", SectionKind::getBSS());
TextSection =
Ctx->getGOFFSection(".text", SectionKind::getText(), nullptr, nullptr);
BSSSection =
Ctx->getGOFFSection(".bss", SectionKind::getBSS(), nullptr, nullptr);
PPA1Section =
Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(), TextSection,
MCConstantExpr::create(GOFF::SK_PPA1, *Ctx));
}
void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {

View File

@ -819,13 +819,253 @@ void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {
emitStackMaps(SM);
}
void SystemZAsmPrinter::emitFunctionBodyEnd() {
if (TM.getTargetTriple().isOSzOS()) {
// Emit symbol for the end of function if the z/OS target streamer
// is used. This is needed to calculate the size of the function.
MCSymbol *FnEndSym = createTempSymbol("func_end");
OutStreamer->emitLabel(FnEndSym);
OutStreamer->PushSection();
OutStreamer->SwitchSection(getObjFileLowering().getPPA1Section());
emitPPA1(FnEndSym);
OutStreamer->PopSection();
CurrentFnPPA1Sym = nullptr;
CurrentFnEPMarkerSym = nullptr;
}
}
static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
bool StackProtector, bool FPRMask, bool VRMask) {
enum class PPA1Flag1 : uint8_t {
DSA64Bit = (0x80 >> 0),
VarArg = (0x80 >> 7),
LLVM_MARK_AS_BITMASK_ENUM(DSA64Bit)
};
enum class PPA1Flag2 : uint8_t {
ExternalProcedure = (0x80 >> 0),
STACKPROTECTOR = (0x80 >> 3),
LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure)
};
enum class PPA1Flag3 : uint8_t {
FPRMask = (0x80 >> 2),
LLVM_MARK_AS_BITMASK_ENUM(FPRMask)
};
enum class PPA1Flag4 : uint8_t {
EPMOffsetPresent = (0x80 >> 0),
VRMask = (0x80 >> 2),
ProcedureNamePresent = (0x80 >> 7),
LLVM_MARK_AS_BITMASK_ENUM(EPMOffsetPresent)
};
// Declare optional section flags that can be modified.
auto Flags1 = PPA1Flag1(0);
auto Flags2 = PPA1Flag2::ExternalProcedure;
auto Flags3 = PPA1Flag3(0);
auto Flags4 = PPA1Flag4::EPMOffsetPresent | PPA1Flag4::ProcedureNamePresent;
Flags1 |= PPA1Flag1::DSA64Bit;
if (VarArg)
Flags1 |= PPA1Flag1::VarArg;
if (StackProtector)
Flags2 |= PPA1Flag2::STACKPROTECTOR;
// SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in.
if (FPRMask)
Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag.
if (VRMask)
Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag.
OutStreamer->AddComment("PPA1 Flags 1");
if ((Flags1 & PPA1Flag1::DSA64Bit) == PPA1Flag1::DSA64Bit)
OutStreamer->AddComment(" Bit 0: 1 = 64-bit DSA");
else
OutStreamer->AddComment(" Bit 0: 0 = 32-bit DSA");
if ((Flags1 & PPA1Flag1::VarArg) == PPA1Flag1::VarArg)
OutStreamer->AddComment(" Bit 7: 1 = Vararg function");
OutStreamer->emitInt8(static_cast<uint8_t>(Flags1)); // Flags 1.
OutStreamer->AddComment("PPA1 Flags 2");
if ((Flags2 & PPA1Flag2::ExternalProcedure) == PPA1Flag2::ExternalProcedure)
OutStreamer->AddComment(" Bit 0: 1 = External procedure");
if ((Flags2 & PPA1Flag2::STACKPROTECTOR) == PPA1Flag2::STACKPROTECTOR)
OutStreamer->AddComment(" Bit 3: 1 = STACKPROTECT is enabled");
else
OutStreamer->AddComment(" Bit 3: 0 = STACKPROTECT is not enabled");
OutStreamer->emitInt8(static_cast<uint8_t>(Flags2)); // Flags 2.
OutStreamer->AddComment("PPA1 Flags 3");
if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask)
OutStreamer->AddComment(" Bit 2: 1 = FP Reg Mask is in optional area");
OutStreamer->emitInt8(
static_cast<uint8_t>(Flags3)); // Flags 3 (optional sections).
OutStreamer->AddComment("PPA1 Flags 4");
if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask)
OutStreamer->AddComment(" Bit 2: 1 = Vector Reg Mask is in optional area");
OutStreamer->emitInt8(static_cast<uint8_t>(
Flags4)); // Flags 4 (optional sections, always emit these).
}
void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
const auto TargetHasVector = Subtarget.hasVector();
const SystemZMachineFunctionInfo *ZFI =
MF->getInfo<SystemZMachineFunctionInfo>();
const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>(
Subtarget.getFrameLowering());
const MachineFrameInfo &MFFrame = MF->getFrameInfo();
// Get saved GPR/FPR/VPR masks.
const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
uint16_t SavedGPRMask = 0;
uint16_t SavedFPRMask = 0;
uint8_t SavedVRMask = 0;
int64_t OffsetFPR = 0;
int64_t OffsetVR = 0;
const int64_t TopOfStack =
MFFrame.getOffsetAdjustment() + MFFrame.getStackSize();
// Loop over the spilled registers. The CalleeSavedInfo can't be used because
// it does not contain all spilled registers.
for (unsigned I = ZFI->getSpillGPRRegs().LowGPR,
E = ZFI->getSpillGPRRegs().HighGPR;
I && E && I <= E; ++I) {
unsigned V = TRI->getEncodingValue((Register)I);
assert(V < 16 && "GPR index out of range");
SavedGPRMask |= 1 << (15 - V);
}
for (auto &CS : CSI) {
unsigned Reg = CS.getReg();
unsigned I = TRI->getEncodingValue(Reg);
if (SystemZ::FP64BitRegClass.contains(Reg)) {
assert(I < 16 && "FPR index out of range");
SavedFPRMask |= 1 << (15 - I);
int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
if (Temp < OffsetFPR)
OffsetFPR = Temp;
} else if (SystemZ::VR128BitRegClass.contains(Reg)) {
assert(I >= 16 && I <= 23 && "VPR index out of range");
unsigned BitNum = I - 16;
SavedVRMask |= 1 << (7 - BitNum);
int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
if (Temp < OffsetVR)
OffsetVR = Temp;
}
}
// Adjust the offset.
OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0;
OffsetVR += (OffsetVR < 0) ? TopOfStack : 0;
// Get alloca register.
uint8_t FrameReg = TRI->getEncodingValue(TRI->getFrameRegister(*MF));
uint8_t AllocaReg = ZFL->hasFP(*MF) ? FrameReg : 0;
assert(AllocaReg < 16 && "Can't have alloca register larger than 15");
// Build FPR save area offset.
uint32_t FrameAndFPROffset = 0;
if (SavedFPRMask) {
uint64_t FPRSaveAreaOffset = OffsetFPR;
assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range");
FrameAndFPROffset = FPRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.
FrameAndFPROffset |= FrameReg << 28; // Put into top 4 bits.
}
// Build VR save area offset.
uint32_t FrameAndVROffset = 0;
if (TargetHasVector && SavedVRMask) {
uint64_t VRSaveAreaOffset = OffsetVR;
assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range");
FrameAndVROffset = VRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.
FrameAndVROffset |= FrameReg << 28; // Put into top 4 bits.
}
// Emit PPA1 section.
OutStreamer->AddComment("PPA1");
OutStreamer->emitLabel(CurrentFnPPA1Sym);
OutStreamer->AddComment("Version");
OutStreamer->emitInt8(0x02); // Version.
OutStreamer->AddComment("LE Signature X'CE'");
OutStreamer->emitInt8(0xCE); // CEL signature.
OutStreamer->AddComment("Saved GPR Mask");
OutStreamer->emitInt16(SavedGPRMask);
emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(),
MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0,
TargetHasVector && SavedVRMask != 0);
OutStreamer->AddComment("Length/4 of Parms");
OutStreamer->emitInt16(
static_cast<uint16_t>(MFFrame.getMaxCallFrameSize() / 4)); // Parms/4.
OutStreamer->AddComment("Length of Code");
OutStreamer->emitAbsoluteSymbolDiff(FnEndSym, CurrentFnEPMarkerSym, 4);
// Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).
if (SavedFPRMask) {
OutStreamer->AddComment("FPR mask");
OutStreamer->emitInt16(SavedFPRMask);
OutStreamer->AddComment("AR mask");
OutStreamer->emitInt16(0); // AR Mask, unused currently.
OutStreamer->AddComment("FPR Save Area Locator");
OutStreamer->AddComment(Twine(" Bit 0-3: Register R")
.concat(utostr(FrameAndFPROffset >> 28))
.str());
OutStreamer->AddComment(Twine(" Bit 4-31: Offset ")
.concat(utostr(FrameAndFPROffset & 0x0FFFFFFF))
.str());
OutStreamer->emitInt32(FrameAndFPROffset); // Offset to FPR save area with
// register to add value to
// (alloca reg).
}
// Emit saved VR mask to VR save area.
if (TargetHasVector && SavedVRMask) {
OutStreamer->AddComment("VR mask");
OutStreamer->emitInt8(SavedVRMask);
OutStreamer->emitInt8(0); // Reserved.
OutStreamer->emitInt16(0); // Also reserved.
OutStreamer->AddComment("VR Save Area Locator");
OutStreamer->AddComment(Twine(" Bit 0-3: Register R")
.concat(utostr(FrameAndVROffset >> 28))
.str());
OutStreamer->AddComment(Twine(" Bit 4-31: Offset ")
.concat(utostr(FrameAndVROffset & 0x0FFFFFFF))
.str());
OutStreamer->emitInt32(FrameAndVROffset);
}
// Emit offset to entry point optional section (0x80 of flags 4).
OutStreamer->emitAbsoluteSymbolDiff(CurrentFnEPMarkerSym, CurrentFnPPA1Sym,
4);
}
void SystemZAsmPrinter::emitFunctionEntryLabel() {
const SystemZSubtarget &Subtarget =
static_cast<const SystemZSubtarget &>(MF->getSubtarget());
if (Subtarget.getTargetTriple().isOSzOS()) {
MCContext &OutContext = OutStreamer->getContext();
MCSymbol *EPMarkerSym = OutContext.createTempSymbol("CM_", true);
// Save information for later use.
std::string N(MF->getFunction().hasName()
? Twine(MF->getFunction().getName()).concat("_").str()
: "");
CurrentFnEPMarkerSym =
OutContext.createTempSymbol(Twine("EPM_").concat(N).str(), true);
CurrentFnPPA1Sym =
OutContext.createTempSymbol(Twine("PPA1_").concat(N).str(), true);
// EntryPoint Marker
const MachineFrameInfo &MFFrame = MF->getFrameInfo();
@ -844,11 +1084,14 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() {
// Emit entry point marker section.
OutStreamer->AddComment("XPLINK Routine Layout Entry");
OutStreamer->emitLabel(EPMarkerSym);
OutStreamer->emitLabel(CurrentFnEPMarkerSym);
OutStreamer->AddComment("Eyecatcher 0x00C300C500C500");
OutStreamer->emitIntValueInHex(0x00C300C500C500, 7); // Eyecatcher.
OutStreamer->AddComment("Mark Type C'1'");
OutStreamer->emitInt8(0xF1); // Mark Type.
OutStreamer->AddComment("Offset to PPA1");
OutStreamer->emitAbsoluteSymbolDiff(CurrentFnPPA1Sym, CurrentFnEPMarkerSym,
4);
if (OutStreamer->isVerboseAsm()) {
OutStreamer->AddComment("DSA Size 0x" + Twine::utohexstr(DSASize));
OutStreamer->AddComment("Entry Flags");

View File

@ -26,6 +26,8 @@ class raw_ostream;
class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
private:
StackMaps SM;
MCSymbol *CurrentFnPPA1Sym; // PPA1 Symbol.
MCSymbol *CurrentFnEPMarkerSym; // Entry Point Marker.
SystemZTargetStreamer *getTargetStreamer() {
MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
@ -45,9 +47,12 @@ private:
BASR33 = 7, // b'x111' == BASR r3,r3
};
void emitPPA1(MCSymbol *FnEndSym);
public:
SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), SM(*this) {}
: AsmPrinter(TM, std::move(Streamer)), SM(*this),
CurrentFnPPA1Sym(nullptr), CurrentFnEPMarkerSym(nullptr) {}
// Override AsmPrinter.
StringRef getPassName() const override { return "SystemZ Assembly Printer"; }
@ -64,6 +69,7 @@ public:
return AsmPrinter::doInitialization(M);
}
void emitFunctionEntryLabel() override;
void emitFunctionBodyEnd() override;
private:
void emitCallInformation(CallType CT);

View File

@ -1,7 +1,7 @@
; RUN: llc -mtriple s390x-ibm-zos < %s | FileCheck %s
; REQUIRES: systemz-registered-target
; CHECK: @@CM_0: * @void_test
; CHECK: @@EPM_void_test_0: * @void_test
; CHECK: * XPLINK Routine Layout Entry
; CHECK: .long 12779717 * Eyecatcher 0x00C300C500C500
; CHECK: .short 197
@ -10,6 +10,24 @@
; CHECK: .long 128 * DSA Size 0x80
; CHECK: * Entry Flags
; CHECK: * Bit 2: 0 = Does not use alloca
; CHECK: @@func_end0:
; CHECK: .section ".ppa1"
; CHECK: @@PPA1_void_test_0: * PPA1
; CHECK: .byte 2 * Version
; CHECK: .byte 206 * LE Signature X'CE'
; CHECK: .short 768 * Saved GPR Mask
; CHECK: .byte 128 * PPA1 Flags 1
; CHECK: * Bit 0: 1 = 64-bit DSA
; CHECK: .byte 128 * PPA1 Flags 2
; CHECK: * Bit 0: 1 = External procedure
; CHECK: * Bit 3: 0 = STACKPROTECT is not enabled
; CHECK: .byte 0 * PPA1 Flags 3
; CHECK: .byte 129 * PPA1 Flags 4
; CHECK: .short 0 * Length/4 of Parms
; CHECK: .long @@func_end0-@@EPM_void_test_0 * Length of Code
; CHECK: .long @@EPM_void_test_0-@@PPA1_void_test_0
; CHECK: .section ".text"
; CHECK: * -- End function
define void @void_test() {
entry:
ret void