diff options
Diffstat (limited to 'llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp')
| -rw-r--r-- | llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 253 |
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 |
