aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp')
-rw-r--r--llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp253
1 files changed, 245 insertions, 8 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index afebdd3f6149..3186002c57d9 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -27,6 +27,10 @@
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
@@ -349,9 +353,9 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
}
EmitToStreamer(*OutStreamer, MCInstBuilder(Op)
.addReg(TargetReg)
- .addReg(IndexReg)
+ .addReg(ADAReg)
.addImm(Disp)
- .addReg(ADAReg));
+ .addReg(IndexReg));
return;
}
@@ -952,6 +956,7 @@ void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {
auto TT = OutContext.getTargetTriple();
if (TT.isOSzOS()) {
emitADASection();
+ emitIDRLSection(M);
}
emitAttributes(M);
}
@@ -1025,6 +1030,72 @@ void SystemZAsmPrinter::emitADASection() {
OutStreamer->popSection();
}
+static std::string getProductID(Module &M) {
+ std::string ProductID;
+ if (auto *MD = M.getModuleFlag("zos_product_id"))
+ ProductID = cast<MDString>(MD)->getString().str();
+ if (ProductID.empty())
+ ProductID = "LLVM";
+ return ProductID;
+}
+
+static uint32_t getProductVersion(Module &M) {
+ if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>(
+ M.getModuleFlag("zos_product_major_version")))
+ return VersionVal->getZExtValue();
+ return LLVM_VERSION_MAJOR;
+}
+
+static uint32_t getProductRelease(Module &M) {
+ if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>(
+ M.getModuleFlag("zos_product_minor_version")))
+ return ReleaseVal->getZExtValue();
+ return LLVM_VERSION_MINOR;
+}
+
+static uint32_t getProductPatch(Module &M) {
+ if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>(
+ M.getModuleFlag("zos_product_patchlevel")))
+ return PatchVal->getZExtValue();
+ return LLVM_VERSION_PATCH;
+}
+
+static time_t getTranslationTime(Module &M) {
+ std::time_t Time = 0;
+ if (auto *Val = mdconst::extract_or_null<ConstantInt>(
+ M.getModuleFlag("zos_translation_time"))) {
+ long SecondsSinceEpoch = Val->getSExtValue();
+ Time = static_cast<time_t>(SecondsSinceEpoch);
+ }
+ return Time;
+}
+
+void SystemZAsmPrinter::emitIDRLSection(Module &M) {
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(getObjFileLowering().getIDRLSection());
+ constexpr unsigned IDRLDataLength = 30;
+ std::time_t Time = getTranslationTime(M);
+
+ uint32_t ProductVersion = getProductVersion(M);
+ uint32_t ProductRelease = getProductRelease(M);
+
+ std::string ProductID = getProductID(M);
+
+ SmallString<IDRLDataLength + 1> TempStr;
+ raw_svector_ostream O(TempStr);
+ O << formatv("{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}",
+ ProductID.substr(0, 10).c_str(), ProductVersion, ProductRelease,
+ llvm::sys::toUtcTime(Time), "0");
+ SmallString<IDRLDataLength> Data;
+ ConverterEBCDIC::convertToEBCDIC(TempStr, Data);
+
+ OutStreamer->emitInt8(0); // Reserved.
+ OutStreamer->emitInt8(3); // Format.
+ OutStreamer->emitInt16(IDRLDataLength); // Length.
+ OutStreamer->emitBytes(Data.str());
+ OutStreamer->popSection();
+}
+
void SystemZAsmPrinter::emitFunctionBodyEnd() {
if (TM.getTargetTriple().isOSzOS()) {
// Emit symbol for the end of function if the z/OS target streamer
@@ -1043,7 +1114,8 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
}
static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
- bool StackProtector, bool FPRMask, bool VRMask) {
+ bool StackProtector, bool FPRMask, bool VRMask,
+ bool HasName) {
enum class PPA1Flag1 : uint8_t {
DSA64Bit = (0x80 >> 0),
VarArg = (0x80 >> 7),
@@ -1069,7 +1141,7 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
auto Flags1 = PPA1Flag1(0);
auto Flags2 = PPA1Flag2::ExternalProcedure;
auto Flags3 = PPA1Flag3(0);
- auto Flags4 = PPA1Flag4::EPMOffsetPresent | PPA1Flag4::ProcedureNamePresent;
+ auto Flags4 = PPA1Flag4::EPMOffsetPresent;
Flags1 |= PPA1Flag1::DSA64Bit;
@@ -1086,6 +1158,9 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
if (VRMask)
Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag.
+ if (HasName)
+ Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block.
+
OutStreamer->AddComment("PPA1 Flags 1");
if ((Flags1 & PPA1Flag1::DSA64Bit) == PPA1Flag1::DSA64Bit)
OutStreamer->AddComment(" Bit 0: 1 = 64-bit DSA");
@@ -1113,11 +1188,40 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
OutStreamer->AddComment("PPA1 Flags 4");
if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask)
OutStreamer->AddComment(" Bit 2: 1 = Vector Reg Mask is in optional area");
+ if ((Flags4 & PPA1Flag4::ProcedureNamePresent) ==
+ PPA1Flag4::ProcedureNamePresent)
+ OutStreamer->AddComment(" Bit 7: 1 = Name Length and Name");
OutStreamer->emitInt8(static_cast<uint8_t>(
Flags4)); // Flags 4 (optional sections, always emit these).
}
+static void emitPPA1Name(std::unique_ptr<MCStreamer> &OutStreamer,
+ StringRef OutName) {
+ size_t NameSize = OutName.size();
+ uint16_t OutSize;
+ if (NameSize < UINT16_MAX) {
+ OutSize = static_cast<uint16_t>(NameSize);
+ } else {
+ OutName = OutName.substr(0, UINT16_MAX);
+ OutSize = UINT16_MAX;
+ }
+ // Emit padding to ensure that the next optional field word-aligned.
+ uint8_t ExtraZeros = 4 - ((2 + OutSize) % 4);
+
+ SmallString<512> OutnameConv;
+ ConverterEBCDIC::convertToEBCDIC(OutName, OutnameConv);
+ OutName = OutnameConv.str();
+
+ OutStreamer->AddComment("Length of Name");
+ OutStreamer->emitInt16(OutSize);
+ OutStreamer->AddComment("Name of Function");
+ OutStreamer->emitBytes(OutName);
+ OutStreamer->emitZeros(ExtraZeros);
+}
+
void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
+ assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");
+
const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
const auto TargetHasVector = Subtarget.hasVector();
@@ -1207,10 +1311,15 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
OutStreamer->emitInt8(0xCE); // CEL signature.
OutStreamer->AddComment("Saved GPR Mask");
OutStreamer->emitInt16(SavedGPRMask);
+ OutStreamer->AddComment("Offset to PPA2");
+ OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CurrentFnPPA1Sym, 4);
+
+ bool HasName =
+ MF->getFunction().hasName() && MF->getFunction().getName().size() > 0;
emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(),
MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0,
- TargetHasVector && SavedVRMask != 0);
+ TargetHasVector && SavedVRMask != 0, HasName);
OutStreamer->AddComment("Length/4 of Parms");
OutStreamer->emitInt16(
@@ -1252,11 +1361,133 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
OutStreamer->emitInt32(FrameAndVROffset);
}
+ // Emit name length and name optional section (0x01 of flags 4)
+ if (HasName)
+ emitPPA1Name(OutStreamer, MF->getFunction().getName());
+
// Emit offset to entry point optional section (0x80 of flags 4).
OutStreamer->emitAbsoluteSymbolDiff(CurrentFnEPMarkerSym, CurrentFnPPA1Sym,
4);
}
+void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
+ if (TM.getTargetTriple().isOSzOS())
+ emitPPA2(M);
+ AsmPrinter::emitStartOfAsmFile(M);
+}
+
+void SystemZAsmPrinter::emitPPA2(Module &M) {
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(getObjFileLowering().getPPA2Section());
+ MCContext &OutContext = OutStreamer->getContext();
+ // Make CELQSTRT symbol.
+ const char *StartSymbolName = "CELQSTRT";
+ MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
+
+ // Create symbol and assign to class field for use in PPA1.
+ PPA2Sym = OutContext.createTempSymbol("PPA2", false);
+ MCSymbol *DateVersionSym = OutContext.createTempSymbol("DVS", false);
+
+ std::time_t Time = getTranslationTime(M);
+ SmallString<15> CompilationTime; // 14 + null
+ raw_svector_ostream O(CompilationTime);
+ O << formatv("{0:%Y%m%d%H%M%S}", llvm::sys::toUtcTime(Time));
+
+ uint32_t ProductVersion = getProductVersion(M),
+ ProductRelease = getProductRelease(M),
+ ProductPatch = getProductPatch(M);
+
+ SmallString<7> Version; // 6 + null
+ raw_svector_ostream ostr(Version);
+ ostr << formatv("{0,0-2:d}{1,0-2:d}{2,0-2:d}", ProductVersion, ProductRelease,
+ ProductPatch);
+
+ // Drop 0 during conversion.
+ SmallString<sizeof(CompilationTime) - 1> CompilationTimeStr;
+ SmallString<sizeof(Version) - 1> VersionStr;
+
+ ConverterEBCDIC::convertToEBCDIC(CompilationTime, CompilationTimeStr);
+ ConverterEBCDIC::convertToEBCDIC(Version, VersionStr);
+
+ enum class PPA2MemberId : uint8_t {
+ // See z/OS Language Environment Vendor Interfaces v2r5, p.23, for
+ // complete list. Only the C runtime is supported by this backend.
+ LE_C_Runtime = 3,
+ };
+ enum class PPA2MemberSubId : uint8_t {
+ // List of languages using the LE C runtime implementation.
+ C = 0x00,
+ CXX = 0x01,
+ Swift = 0x03,
+ Go = 0x60,
+ LLVMBasedLang = 0xe7,
+ };
+ // PPA2 Flags
+ enum class PPA2Flags : uint8_t {
+ CompileForBinaryFloatingPoint = 0x80,
+ CompiledWithXPLink = 0x01,
+ CompiledUnitASCII = 0x04,
+ HasServiceInfo = 0x20,
+ };
+
+ PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang;
+ if (auto *MD = M.getModuleFlag("zos_cu_language")) {
+ StringRef Language = cast<MDString>(MD)->getString();
+ MemberSubId = StringSwitch<PPA2MemberSubId>(Language)
+ .Case("C", PPA2MemberSubId::C)
+ .Case("C++", PPA2MemberSubId::CXX)
+ .Case("Swift", PPA2MemberSubId::Swift)
+ .Case("Go", PPA2MemberSubId::Go)
+ .Default(PPA2MemberSubId::LLVMBasedLang);
+ }
+
+ // Emit PPA2 section.
+ OutStreamer->emitLabel(PPA2Sym);
+ OutStreamer->emitInt8(static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime));
+ OutStreamer->emitInt8(static_cast<uint8_t>(MemberSubId));
+ OutStreamer->emitInt8(0x22); // Member defined, c370_plist+c370_env
+ OutStreamer->emitInt8(0x04); // Control level 4 (XPLink)
+ OutStreamer->emitAbsoluteSymbolDiff(CELQSTRT, PPA2Sym, 4);
+ OutStreamer->emitInt32(0x00000000);
+ OutStreamer->emitAbsoluteSymbolDiff(DateVersionSym, PPA2Sym, 4);
+ OutStreamer->emitInt32(
+ 0x00000000); // Offset to main entry point, always 0 (so says TR).
+ uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint);
+ Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink);
+
+ if (auto *MD = M.getModuleFlag("zos_le_char_mode")) {
+ const StringRef &CharMode = cast<MDString>(MD)->getString();
+ if (CharMode == "ascii") {
+ Flgs |= static_cast<uint8_t>(
+ PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode.
+ } else if (CharMode != "ebcdic") {
+ report_fatal_error(
+ "Only ascii or ebcdic are valid values for zos_le_char_mode "
+ "metadata");
+ }
+ }
+
+ OutStreamer->emitInt8(Flgs);
+ OutStreamer->emitInt8(0x00); // Reserved.
+ // No MD5 signature before timestamp.
+ // No FLOAT(AFP(VOLATILE)).
+ // Remaining 5 flag bits reserved.
+ OutStreamer->emitInt16(0x0000); // 16 Reserved flag bits.
+
+ // Emit date and version section.
+ OutStreamer->emitLabel(DateVersionSym);
+ OutStreamer->emitBytes(CompilationTimeStr.str());
+ OutStreamer->emitBytes(VersionStr.str());
+
+ OutStreamer->emitInt16(0x0000); // Service level string length.
+
+ // Emit 8 byte alignment.
+ // Emit pointer to PPA2 label.
+ OutStreamer->AddComment("A(PPA2-CELQSTRT)");
+ OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CELQSTRT, 8);
+ OutStreamer->popSection();
+}
+
void SystemZAsmPrinter::emitFunctionEntryLabel() {
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
@@ -1276,14 +1507,16 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() {
// EntryPoint Marker
const MachineFrameInfo &MFFrame = MF->getFrameInfo();
bool IsUsingAlloca = MFFrame.hasVarSizedObjects();
+ uint32_t DSASize = MFFrame.getStackSize();
+ bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty();
- // Set Flags
+ // Set Flags.
uint8_t Flags = 0;
+ if (IsLeaf)
+ Flags |= 0x08;
if (IsUsingAlloca)
Flags |= 0x04;
- uint32_t DSASize = MFFrame.getStackSize();
-
// Combine into top 27 bits of DSASize and bottom 5 bits of Flags.
uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 5
DSAAndFlags |= Flags;
@@ -1301,6 +1534,10 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() {
if (OutStreamer->isVerboseAsm()) {
OutStreamer->AddComment("DSA Size 0x" + Twine::utohexstr(DSASize));
OutStreamer->AddComment("Entry Flags");
+ if (Flags & 0x08)
+ OutStreamer->AddComment(" Bit 1: 1 = Leaf function");
+ else
+ OutStreamer->AddComment(" Bit 1: 0 = Non-leaf function");
if (Flags & 0x04)
OutStreamer->AddComment(" Bit 2: 1 = Uses alloca");
else