blob: aea1c61fabf078aad04bd5264f5bff370f009070 [file]
//==-- 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/MCGOFFStreamer.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());
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();
// 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);
}