-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[SystemZ][z/OS] This change adds support for the PPA2 section in zOS #68926
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
Changes from all commits
78f82bc
5abb1d8
7fcf8f6
df7b6f9
2803491
3b03227
4a13aa6
c0b35d5
1768151
e4346d3
ae6a160
e3d3ed1
c1b9af7
5c4dd07
b23a061
6b3c19f
b5c7bd6
140dff3
754bbec
a2515b7
1d87cf1
772972c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Please note the following: | ||
// + we are checking that the first bytes of the PPA2 are 0x3 0x0 | ||
// for C, and 0x3 0x1 for C++ | ||
// + the label for the PPA2 seems to vary on different versions. | ||
// We try to cover all cases, and use substitution blocks to | ||
// help write the tests. The contents of the PPA2 itself should | ||
// not be different. | ||
// + the [[:space:]] combines the two .byte lines into one pattern. | ||
// This is necessary because if the lines were separated, the first | ||
// .byte (i.e., the one for the 3) would, it seems, also match | ||
// the .byte line below for the 34. | ||
|
||
// RUN: %clang_cc1 -triple s390x-ibm-zos -xc -S -o - %s | FileCheck %s --check-prefix CHECK-C | ||
// CHECK-C: [[PPA2:(.L)|(@@)PPA2]]: | ||
// CHECK-C-NEXT: .byte 3{{[[:space:]]*}}.byte 0 | ||
// CHECK-C-NEXT: .byte 34{{$}} | ||
// CHECK-C-NEXT: .byte {{4}} | ||
// CHECK-C-NEXT: .long {{(CELQSTRT)}}-[[PPA2]] | ||
|
||
// RUN: %clang_cc1 -triple s390x-ibm-zos -xc++ -S -o - %s | FileCheck %s --check-prefix CHECK-CXX | ||
// CHECK-CXX: [[PPA2:(.L)|(@@)PPA2]]: | ||
// CHECK-CXX-NEXT: .byte 3{{[[:space:]]*}}.byte 1 | ||
// CHECK-CXX-NEXT: .byte 34{{$}} | ||
// CHECK-CXX-NEXT: .byte {{4}} | ||
// CHECK-CXX-NEXT: .long {{(CELQSTRT)}}-[[PPA2]] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +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; | ||
|
||
|
@@ -953,6 +956,7 @@ void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { | |
auto TT = OutContext.getTargetTriple(); | ||
if (TT.isOSzOS()) { | ||
emitADASection(); | ||
emitIDRLSection(M); | ||
} | ||
emitAttributes(M); | ||
} | ||
|
@@ -1026,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()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more question about this string - the Length field is hardcoded to 30. Does that mean that there are exactly 30 bytes supposed to always follow here? I'm not sure this is guaranteed by the formatv above ... Also, there doesn't seem to be any test that verifies the layout of this IDRL section, I think we definitely need one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added testing for the IDRL section and fixed the length to be 30 bytes. |
||
OutStreamer->popSection(); | ||
} | ||
|
||
void SystemZAsmPrinter::emitFunctionBodyEnd() { | ||
if (TM.getTargetTriple().isOSzOS()) { | ||
// Emit symbol for the end of function if the z/OS target streamer | ||
|
@@ -1150,6 +1220,8 @@ static void emitPPA1Name(std::unique_ptr<MCStreamer> &OutStreamer, | |
} | ||
|
||
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(); | ||
|
@@ -1239,6 +1311,8 @@ 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; | ||
|
@@ -1296,6 +1370,124 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { | |
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")) { | ||
ysyeda marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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>(); | ||
|
||
|
@@ -1318,7 +1510,7 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() { | |
uint32_t DSASize = MFFrame.getStackSize(); | ||
bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty(); | ||
|
||
// Set Flags | ||
// Set Flags. | ||
uint8_t Flags = 0; | ||
if (IsLeaf) | ||
Flags |= 0x08; | ||
|
Uh oh!
There was an error while loading. Please reload this page.