| //==-- SystemZTargetStreamer.cpp - SystemZ Target Streamer Methods ----------=// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// This file defines SystemZ-specific target streamer classes. | |
| /// These are for implementing support for target-specific assembly directives. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "SystemZTargetStreamer.h" | |
| #include "SystemZHLASMAsmStreamer.h" | |
| #include "llvm/ADT/BitmaskEnum.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/ADT/Twine.h" | |
| #include "llvm/MC/MCAsmInfo.h" | |
| #include "llvm/MC/MCObjectFileInfo.h" | |
| #include "llvm/Support/ConvertEBCDIC.h" | |
| using namespace llvm; | |
| void SystemZTargetStreamer::emitConstantPools() { | |
| // Emit EXRL target instructions. | |
| if (EXRLTargets2Sym.empty()) | |
| return; | |
| // Switch to the .text section. | |
| const MCObjectFileInfo &OFI = *Streamer.getContext().getObjectFileInfo(); | |
| Streamer.switchSection(OFI.getTextSection()); | |
| Streamer.emitValueToAlignment(Align(2)); | |
| for (auto &I : EXRLTargets2Sym) { | |
| Streamer.emitLabel(I.second); | |
| const MCInstSTIPair &MCI_STI = I.first; | |
| Streamer.emitInstruction(MCI_STI.first, *MCI_STI.second); | |
| } | |
| EXRLTargets2Sym.clear(); | |
| } | |
| static void emitPPA1Flags(MCStreamer &OutStreamer, bool VarArg, | |
| bool StackProtector, bool FPRMask, bool VRMask, | |
| bool EHBlock, bool HasArgAreaLength, bool HasName) { | |
| 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 { | |
| HasArgAreaLength = (0x80 >> 1), | |
| FPRMask = (0x80 >> 2), | |
| LLVM_MARK_AS_BITMASK_ENUM(HasArgAreaLength) | |
| }; | |
| enum class PPA1Flag4 : uint8_t { | |
| EPMOffsetPresent = (0x80 >> 0), | |
| VRMask = (0x80 >> 2), | |
| EHBlock = (0x80 >> 3), | |
| 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; | |
| Flags1 |= PPA1Flag1::DSA64Bit; | |
| if (VarArg) | |
| Flags1 |= PPA1Flag1::VarArg; | |
| if (StackProtector) | |
| Flags2 |= PPA1Flag2::STACKPROTECTOR; | |
| if (HasArgAreaLength) | |
| Flags3 |= PPA1Flag3::HasArgAreaLength; // Add emit ArgAreaLength flag. | |
| // 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. | |
| if (EHBlock) | |
| Flags4 |= PPA1Flag4::EHBlock; // Add optional EH block. | |
| if (HasName) | |
| Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block. | |
| OutStreamer.AddComment("PPA1 Flags 1"); | |
| OutStreamer.AddComment(" Bit 0: 1 = 64-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::HasArgAreaLength) == PPA1Flag3::HasArgAreaLength) | |
| OutStreamer.AddComment( | |
| " Bit 1: 1 = Argument Area Length is in optional area"); | |
| 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"); | |
| if ((Flags4 & PPA1Flag4::EHBlock) == PPA1Flag4::EHBlock) | |
| OutStreamer.AddComment(" Bit 3: 1 = C++ EH block"); | |
| 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(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 SystemZTargetzOSStreamer::emitPPA1(PPA1Info &Info) { | |
| assert(PPA2Sym != nullptr && "PPA2 Symbol not defined"); | |
| MCStreamer &OutStreamer = getStreamer(); | |
| MCContext &OutContext = OutStreamer.getContext(); | |
| OutStreamer.emitValueToAlignment(Align(2)); | |
| // Optional Argument Area Length. | |
| // Note: This represents the length of the argument area that we reserve | |
| // in our stack for setting up arguments for calls to other | |
| // routines. If this optional field is not set, LE will reserve | |
| // 128 bytes for the argument area. This optional field is | |
| // created if greater than 128 bytes is required - to guarantee | |
| // the required space is reserved on stack extension in the new | |
| // extension. This optional field is also created if the | |
| // routine has alloca(). This may reduce stack space | |
| // if alloca() call causes a stack extension. | |
| bool HasArgAreaLength = (Info.AllocaReg != 0) || (Info.CallFrameSize > 128); | |
| // The personality function is present if at least one of the displacements is | |
| // larger than zero. | |
| bool HasPersonalityFn = Info.PersonalityADADisp > 0 || Info.GCCEHADADisp > 0; | |
| // Emit PPA1 section. | |
| OutStreamer.AddComment("PPA1"); | |
| OutStreamer.emitLabel(Info.PPA1); | |
| 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(Info.SavedGPRMask); | |
| OutStreamer.AddComment("Offset to PPA2"); | |
| OutStreamer.emitAbsoluteSymbolDiff(PPA2Sym, Info.PPA1, 4); | |
| emitPPA1Flags(OutStreamer, Info.IsVarArg, Info.HasStackProtector, | |
| Info.SavedFPRMask != 0, Info.SavedVRMask != 0, HasPersonalityFn, | |
| HasArgAreaLength, Info.Name.size() > 0); | |
| OutStreamer.AddComment("Length/4 of Parms"); | |
| OutStreamer.emitInt16( | |
| static_cast<uint16_t>(Info.SizeOfFnParams / 4)); // Parms/4. | |
| OutStreamer.AddComment("Length/2 of Prolog "); | |
| if (Info.EndOfProlog) | |
| OutStreamer.emitValue( | |
| createWordDiffExpr(OutContext, Info.EndOfProlog, Info.Fn), 1); | |
| else | |
| OutStreamer.emitInt8(0); | |
| OutStreamer.AddComment("Alloca Reg + Offset/2 to SP Update"); | |
| OutStreamer.AddComment( | |
| Twine(" Bit 0-3: Register R").concat(utostr(Info.AllocaReg)).str()); | |
| OutStreamer.AddComment(" Bit 4-8: Offset "); | |
| const MCExpr *AllocaRegExpr = | |
| MCConstantExpr::create(Info.AllocaReg << 4, OutContext); | |
| if (Info.StackUpdate) | |
| OutStreamer.emitValue( | |
| MCBinaryExpr::createOr( | |
| createWordDiffExpr(OutContext, Info.StackUpdate, Info.Fn), | |
| AllocaRegExpr, OutContext), | |
| 1); | |
| else | |
| OutStreamer.emitValue(AllocaRegExpr, 1); | |
| OutStreamer.AddComment("Length of Code"); | |
| OutStreamer.emitAbsoluteSymbolDiff(Info.FnEnd, Info.EPMarker, 4); | |
| if (HasArgAreaLength) { | |
| OutStreamer.AddComment("Argument Area Length"); | |
| OutStreamer.emitInt32(Info.CallFrameSize); | |
| } | |
| // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3). | |
| if (Info.SavedFPRMask) { | |
| OutStreamer.AddComment("FPR mask"); | |
| OutStreamer.emitInt16(Info.SavedFPRMask); | |
| OutStreamer.AddComment("AR mask"); | |
| OutStreamer.emitInt16(0); // AR Mask, unused currently. | |
| OutStreamer.AddComment("FPR Save Area Locator"); | |
| uint64_t FPRSaveAreaOffset = Info.OffsetFPR; | |
| assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range"); | |
| FPRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits. | |
| OutStreamer.AddComment( | |
| Twine(" Bit 0-3: Register R").concat(utostr(Info.FrameReg))); | |
| OutStreamer.AddComment( | |
| Twine(" Bit 4-31: Offset ").concat(utostr(FPRSaveAreaOffset))); | |
| OutStreamer.emitInt32(FPRSaveAreaOffset | | |
| (Info.FrameReg << 28)); // Offset to FPR save area | |
| // with register to add | |
| // value to (alloca reg). | |
| } | |
| // Emit saved VR mask to VR save area. | |
| if (Info.SavedVRMask) { | |
| OutStreamer.AddComment("VR mask"); | |
| OutStreamer.emitInt8(Info.SavedVRMask); | |
| OutStreamer.emitInt8(0); // Reserved. | |
| OutStreamer.emitInt16(0); // Also reserved. | |
| uint64_t VRSaveAreaOffset = Info.OffsetVR; | |
| assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range"); | |
| VRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits. | |
| OutStreamer.AddComment("VR Save Area Locator"); | |
| OutStreamer.AddComment( | |
| Twine(" Bit 0-3: Register R").concat(utostr(Info.FrameReg))); | |
| OutStreamer.AddComment( | |
| Twine(" Bit 4-31: Offset ").concat(utostr(VRSaveAreaOffset))); | |
| OutStreamer.emitInt32(VRSaveAreaOffset | (Info.FrameReg << 28)); | |
| } | |
| // Emit C++ EH information block. | |
| if (HasPersonalityFn) { | |
| OutStreamer.AddComment("Version"); | |
| OutStreamer.emitInt32(1); | |
| OutStreamer.AddComment("Flags"); | |
| OutStreamer.emitInt32(0); // LSDA field is a WAS offset | |
| OutStreamer.AddComment("Personality routine"); | |
| OutStreamer.emitInt64(Info.PersonalityADADisp); | |
| OutStreamer.AddComment("LSDA location"); | |
| OutStreamer.emitInt64(Info.GCCEHADADisp); | |
| } | |
| // Emit name length and name optional section (0x01 of flags 4) | |
| if (Info.Name.size() > 0) | |
| emitPPA1Name(OutStreamer, Info.Name); | |
| // Emit offset to entry point optional section (0x80 of flags 4). | |
| OutStreamer.emitAbsoluteSymbolDiff(Info.EPMarker, Info.PPA1, 4); | |
| } | |
| void SystemZTargetzOSStreamer::emitConstantPools() { | |
| // Emit EXRL target instructions (base class prolog). | |
| SystemZTargetStreamer::emitConstantPools(); | |
| // Emit deferred PPA1 blocks into the text section. | |
| if (DeferredPPA1.empty()) | |
| return; | |
| const MCObjectFileInfo &OFI = *getStreamer().getContext().getObjectFileInfo(); | |
| getStreamer().switchSection(OFI.getTextSection()); | |
| for (auto &Info : DeferredPPA1) | |
| emitPPA1(Info); | |
| } | |
| SystemZHLASMAsmStreamer &SystemZTargetHLASMStreamer::getHLASMStreamer() { | |
| return static_cast<SystemZHLASMAsmStreamer &>(getStreamer()); | |
| } | |
| // HLASM statements can only perform a single operation at a time | |
| const MCExpr *SystemZTargetHLASMStreamer::createWordDiffExpr( | |
| MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { | |
| assert(Hi && Lo && "Symbols required to calculate expression"); | |
| MCSymbol *Temp = Ctx.createTempSymbol(); | |
| OS << Temp->getName() << " EQU "; | |
| const MCBinaryExpr *TempExpr = MCBinaryExpr::createSub( | |
| MCSymbolRefExpr::create(Hi, Ctx), MCSymbolRefExpr::create(Lo, Ctx), Ctx); | |
| Ctx.getAsmInfo().printExpr(OS, *TempExpr); | |
| OS << "\n"; | |
| return MCBinaryExpr::createLShr(MCSymbolRefExpr::create(Temp, Ctx), | |
| MCConstantExpr::create(1, Ctx), Ctx); | |
| } | |
| const MCExpr *SystemZTargetGOFFStreamer::createWordDiffExpr( | |
| MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { | |
| assert(Hi && Lo && "Symbols required to calculate expression"); | |
| return MCBinaryExpr::createLShr( | |
| MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Ctx), | |
| MCSymbolRefExpr::create(Lo, Ctx), Ctx), | |
| MCConstantExpr::create(1, Ctx), Ctx); | |
| } |