Path: blob/main/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
35266 views
//===-- SystemZAsmPrinter.cpp - SystemZ LLVM assembly printer -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Streams SystemZ assembly language and associated data, in the form of9// MCInsts and MCExprs respectively.10//11//===----------------------------------------------------------------------===//1213#include "SystemZAsmPrinter.h"14#include "MCTargetDesc/SystemZInstPrinter.h"15#include "MCTargetDesc/SystemZMCExpr.h"16#include "SystemZConstantPoolValue.h"17#include "SystemZMCInstLower.h"18#include "TargetInfo/SystemZTargetInfo.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/BinaryFormat/ELF.h"21#include "llvm/CodeGen/MachineModuleInfoImpls.h"22#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"23#include "llvm/IR/Mangler.h"24#include "llvm/IR/Module.h"25#include "llvm/MC/MCExpr.h"26#include "llvm/MC/MCInstBuilder.h"27#include "llvm/MC/MCSectionELF.h"28#include "llvm/MC/MCStreamer.h"29#include "llvm/MC/TargetRegistry.h"30#include "llvm/Support/Chrono.h"31#include "llvm/Support/ConvertEBCDIC.h"32#include "llvm/Support/FormatProviders.h"33#include "llvm/Support/FormatVariadic.h"3435using namespace llvm;3637// Return an RI instruction like MI with opcode Opcode, but with the38// GR64 register operands turned into GR32s.39static MCInst lowerRILow(const MachineInstr *MI, unsigned Opcode) {40if (MI->isCompare())41return MCInstBuilder(Opcode)42.addReg(SystemZMC::getRegAsGR32(MI->getOperand(0).getReg()))43.addImm(MI->getOperand(1).getImm());44else45return MCInstBuilder(Opcode)46.addReg(SystemZMC::getRegAsGR32(MI->getOperand(0).getReg()))47.addReg(SystemZMC::getRegAsGR32(MI->getOperand(1).getReg()))48.addImm(MI->getOperand(2).getImm());49}5051// Return an RI instruction like MI with opcode Opcode, but with the52// GR64 register operands turned into GRH32s.53static MCInst lowerRIHigh(const MachineInstr *MI, unsigned Opcode) {54if (MI->isCompare())55return MCInstBuilder(Opcode)56.addReg(SystemZMC::getRegAsGRH32(MI->getOperand(0).getReg()))57.addImm(MI->getOperand(1).getImm());58else59return MCInstBuilder(Opcode)60.addReg(SystemZMC::getRegAsGRH32(MI->getOperand(0).getReg()))61.addReg(SystemZMC::getRegAsGRH32(MI->getOperand(1).getReg()))62.addImm(MI->getOperand(2).getImm());63}6465// Return an RI instruction like MI with opcode Opcode, but with the66// R2 register turned into a GR64.67static MCInst lowerRIEfLow(const MachineInstr *MI, unsigned Opcode) {68return MCInstBuilder(Opcode)69.addReg(MI->getOperand(0).getReg())70.addReg(MI->getOperand(1).getReg())71.addReg(SystemZMC::getRegAsGR64(MI->getOperand(2).getReg()))72.addImm(MI->getOperand(3).getImm())73.addImm(MI->getOperand(4).getImm())74.addImm(MI->getOperand(5).getImm());75}7677static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) {78StringRef Name = "__tls_get_offset";79return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),80MCSymbolRefExpr::VK_PLT,81Context);82}8384static const MCSymbolRefExpr *getGlobalOffsetTable(MCContext &Context) {85StringRef Name = "_GLOBAL_OFFSET_TABLE_";86return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),87MCSymbolRefExpr::VK_None,88Context);89}9091// MI is an instruction that accepts an optional alignment hint,92// and which was already lowered to LoweredMI. If the alignment93// of the original memory operand is known, update LoweredMI to94// an instruction with the corresponding hint set.95static void lowerAlignmentHint(const MachineInstr *MI, MCInst &LoweredMI,96unsigned Opcode) {97if (MI->memoperands_empty())98return;99100Align Alignment = Align(16);101for (MachineInstr::mmo_iterator MMOI = MI->memoperands_begin(),102EE = MI->memoperands_end(); MMOI != EE; ++MMOI)103if ((*MMOI)->getAlign() < Alignment)104Alignment = (*MMOI)->getAlign();105106unsigned AlignmentHint = 0;107if (Alignment >= Align(16))108AlignmentHint = 4;109else if (Alignment >= Align(8))110AlignmentHint = 3;111if (AlignmentHint == 0)112return;113114LoweredMI.setOpcode(Opcode);115LoweredMI.addOperand(MCOperand::createImm(AlignmentHint));116}117118// MI loads the high part of a vector from memory. Return an instruction119// that uses replicating vector load Opcode to do the same thing.120static MCInst lowerSubvectorLoad(const MachineInstr *MI, unsigned Opcode) {121return MCInstBuilder(Opcode)122.addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg()))123.addReg(MI->getOperand(1).getReg())124.addImm(MI->getOperand(2).getImm())125.addReg(MI->getOperand(3).getReg());126}127128// MI stores the high part of a vector to memory. Return an instruction129// that uses elemental vector store Opcode to do the same thing.130static MCInst lowerSubvectorStore(const MachineInstr *MI, unsigned Opcode) {131return MCInstBuilder(Opcode)132.addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg()))133.addReg(MI->getOperand(1).getReg())134.addImm(MI->getOperand(2).getImm())135.addReg(MI->getOperand(3).getReg())136.addImm(0);137}138139// The XPLINK ABI requires that a no-op encoding the call type is emitted after140// each call to a subroutine. This information can be used by the called141// function to determine its entry point, e.g. for generating a backtrace. The142// call type is encoded as a register number in the bcr instruction. See143// enumeration CallType for the possible values.144void SystemZAsmPrinter::emitCallInformation(CallType CT) {145EmitToStreamer(*OutStreamer,146MCInstBuilder(SystemZ::BCRAsm)147.addImm(0)148.addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));149}150151uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,152unsigned SlotKind) {153auto Key = std::make_pair(Sym, SlotKind);154auto It = Displacements.find(Key);155156if (It != Displacements.end())157return (*It).second;158159// Determine length of descriptor.160uint32_t Length;161switch (SlotKind) {162case SystemZII::MO_ADA_DIRECT_FUNC_DESC:163Length = 2 * PointerSize;164break;165default:166Length = PointerSize;167break;168}169170uint32_t Displacement = NextDisplacement;171Displacements[std::make_pair(Sym, SlotKind)] = NextDisplacement;172NextDisplacement += Length;173174return Displacement;175}176177uint32_t178SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {179MCSymbol *Sym;180if (MO.getType() == MachineOperand::MO_GlobalAddress) {181const GlobalValue *GV = MO.getGlobal();182Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);183assert(Sym && "No symbol");184} else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {185const char *SymName = MO.getSymbolName();186Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(SymName);187assert(Sym && "No symbol");188} else189llvm_unreachable("Unexpected operand type");190191unsigned ADAslotType = MO.getTargetFlags();192return insert(Sym, ADAslotType);193}194195void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {196SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),197getSubtargetInfo().getFeatureBits());198199SystemZMCInstLower Lower(MF->getContext(), *this);200MCInst LoweredMI;201switch (MI->getOpcode()) {202case SystemZ::Return:203LoweredMI = MCInstBuilder(SystemZ::BR)204.addReg(SystemZ::R14D);205break;206207case SystemZ::Return_XPLINK:208LoweredMI = MCInstBuilder(SystemZ::B)209.addReg(SystemZ::R7D)210.addImm(2)211.addReg(0);212break;213214case SystemZ::CondReturn:215LoweredMI = MCInstBuilder(SystemZ::BCR)216.addImm(MI->getOperand(0).getImm())217.addImm(MI->getOperand(1).getImm())218.addReg(SystemZ::R14D);219break;220221case SystemZ::CondReturn_XPLINK:222LoweredMI = MCInstBuilder(SystemZ::BC)223.addImm(MI->getOperand(0).getImm())224.addImm(MI->getOperand(1).getImm())225.addReg(SystemZ::R7D)226.addImm(2)227.addReg(0);228break;229230case SystemZ::CRBReturn:231LoweredMI = MCInstBuilder(SystemZ::CRB)232.addReg(MI->getOperand(0).getReg())233.addReg(MI->getOperand(1).getReg())234.addImm(MI->getOperand(2).getImm())235.addReg(SystemZ::R14D)236.addImm(0);237break;238239case SystemZ::CGRBReturn:240LoweredMI = MCInstBuilder(SystemZ::CGRB)241.addReg(MI->getOperand(0).getReg())242.addReg(MI->getOperand(1).getReg())243.addImm(MI->getOperand(2).getImm())244.addReg(SystemZ::R14D)245.addImm(0);246break;247248case SystemZ::CIBReturn:249LoweredMI = MCInstBuilder(SystemZ::CIB)250.addReg(MI->getOperand(0).getReg())251.addImm(MI->getOperand(1).getImm())252.addImm(MI->getOperand(2).getImm())253.addReg(SystemZ::R14D)254.addImm(0);255break;256257case SystemZ::CGIBReturn:258LoweredMI = MCInstBuilder(SystemZ::CGIB)259.addReg(MI->getOperand(0).getReg())260.addImm(MI->getOperand(1).getImm())261.addImm(MI->getOperand(2).getImm())262.addReg(SystemZ::R14D)263.addImm(0);264break;265266case SystemZ::CLRBReturn:267LoweredMI = MCInstBuilder(SystemZ::CLRB)268.addReg(MI->getOperand(0).getReg())269.addReg(MI->getOperand(1).getReg())270.addImm(MI->getOperand(2).getImm())271.addReg(SystemZ::R14D)272.addImm(0);273break;274275case SystemZ::CLGRBReturn:276LoweredMI = MCInstBuilder(SystemZ::CLGRB)277.addReg(MI->getOperand(0).getReg())278.addReg(MI->getOperand(1).getReg())279.addImm(MI->getOperand(2).getImm())280.addReg(SystemZ::R14D)281.addImm(0);282break;283284case SystemZ::CLIBReturn:285LoweredMI = MCInstBuilder(SystemZ::CLIB)286.addReg(MI->getOperand(0).getReg())287.addImm(MI->getOperand(1).getImm())288.addImm(MI->getOperand(2).getImm())289.addReg(SystemZ::R14D)290.addImm(0);291break;292293case SystemZ::CLGIBReturn:294LoweredMI = MCInstBuilder(SystemZ::CLGIB)295.addReg(MI->getOperand(0).getReg())296.addImm(MI->getOperand(1).getImm())297.addImm(MI->getOperand(2).getImm())298.addReg(SystemZ::R14D)299.addImm(0);300break;301302case SystemZ::CallBRASL_XPLINK64:303EmitToStreamer(*OutStreamer,304MCInstBuilder(SystemZ::BRASL)305.addReg(SystemZ::R7D)306.addExpr(Lower.getExpr(MI->getOperand(0),307MCSymbolRefExpr::VK_PLT)));308emitCallInformation(CallType::BRASL7);309return;310311case SystemZ::CallBASR_XPLINK64:312EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)313.addReg(SystemZ::R7D)314.addReg(MI->getOperand(0).getReg()));315emitCallInformation(CallType::BASR76);316return;317318case SystemZ::CallBASR_STACKEXT:319EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)320.addReg(SystemZ::R3D)321.addReg(MI->getOperand(0).getReg()));322emitCallInformation(CallType::BASR33);323return;324325case SystemZ::ADA_ENTRY_VALUE:326case SystemZ::ADA_ENTRY: {327const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();328const SystemZInstrInfo *TII = Subtarget.getInstrInfo();329uint32_t Disp = ADATable.insert(MI->getOperand(1));330Register TargetReg = MI->getOperand(0).getReg();331332Register ADAReg = MI->getOperand(2).getReg();333Disp += MI->getOperand(3).getImm();334bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY;335336unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG;337unsigned Op = TII->getOpcodeForOffset(Op0, Disp);338339Register IndexReg = 0;340if (!Op) {341if (TargetReg != ADAReg) {342IndexReg = TargetReg;343// Use TargetReg to store displacement.344EmitToStreamer(345*OutStreamer,346MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp));347} else348EmitToStreamer(349*OutStreamer,350MCInstBuilder(SystemZ::ALGFI).addReg(TargetReg).addImm(Disp));351Disp = 0;352Op = Op0;353}354EmitToStreamer(*OutStreamer, MCInstBuilder(Op)355.addReg(TargetReg)356.addReg(ADAReg)357.addImm(Disp)358.addReg(IndexReg));359360return;361}362case SystemZ::CallBRASL:363LoweredMI = MCInstBuilder(SystemZ::BRASL)364.addReg(SystemZ::R14D)365.addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_PLT));366break;367368case SystemZ::CallBASR:369LoweredMI = MCInstBuilder(SystemZ::BASR)370.addReg(SystemZ::R14D)371.addReg(MI->getOperand(0).getReg());372break;373374case SystemZ::CallJG:375LoweredMI = MCInstBuilder(SystemZ::JG)376.addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_PLT));377break;378379case SystemZ::CallBRCL:380LoweredMI = MCInstBuilder(SystemZ::BRCL)381.addImm(MI->getOperand(0).getImm())382.addImm(MI->getOperand(1).getImm())383.addExpr(Lower.getExpr(MI->getOperand(2), MCSymbolRefExpr::VK_PLT));384break;385386case SystemZ::CallBR:387LoweredMI = MCInstBuilder(SystemZ::BR)388.addReg(MI->getOperand(0).getReg());389break;390391case SystemZ::CallBCR:392LoweredMI = MCInstBuilder(SystemZ::BCR)393.addImm(MI->getOperand(0).getImm())394.addImm(MI->getOperand(1).getImm())395.addReg(MI->getOperand(2).getReg());396break;397398case SystemZ::CRBCall:399LoweredMI = MCInstBuilder(SystemZ::CRB)400.addReg(MI->getOperand(0).getReg())401.addReg(MI->getOperand(1).getReg())402.addImm(MI->getOperand(2).getImm())403.addReg(MI->getOperand(3).getReg())404.addImm(0);405break;406407case SystemZ::CGRBCall:408LoweredMI = MCInstBuilder(SystemZ::CGRB)409.addReg(MI->getOperand(0).getReg())410.addReg(MI->getOperand(1).getReg())411.addImm(MI->getOperand(2).getImm())412.addReg(MI->getOperand(3).getReg())413.addImm(0);414break;415416case SystemZ::CIBCall:417LoweredMI = MCInstBuilder(SystemZ::CIB)418.addReg(MI->getOperand(0).getReg())419.addImm(MI->getOperand(1).getImm())420.addImm(MI->getOperand(2).getImm())421.addReg(MI->getOperand(3).getReg())422.addImm(0);423break;424425case SystemZ::CGIBCall:426LoweredMI = MCInstBuilder(SystemZ::CGIB)427.addReg(MI->getOperand(0).getReg())428.addImm(MI->getOperand(1).getImm())429.addImm(MI->getOperand(2).getImm())430.addReg(MI->getOperand(3).getReg())431.addImm(0);432break;433434case SystemZ::CLRBCall:435LoweredMI = MCInstBuilder(SystemZ::CLRB)436.addReg(MI->getOperand(0).getReg())437.addReg(MI->getOperand(1).getReg())438.addImm(MI->getOperand(2).getImm())439.addReg(MI->getOperand(3).getReg())440.addImm(0);441break;442443case SystemZ::CLGRBCall:444LoweredMI = MCInstBuilder(SystemZ::CLGRB)445.addReg(MI->getOperand(0).getReg())446.addReg(MI->getOperand(1).getReg())447.addImm(MI->getOperand(2).getImm())448.addReg(MI->getOperand(3).getReg())449.addImm(0);450break;451452case SystemZ::CLIBCall:453LoweredMI = MCInstBuilder(SystemZ::CLIB)454.addReg(MI->getOperand(0).getReg())455.addImm(MI->getOperand(1).getImm())456.addImm(MI->getOperand(2).getImm())457.addReg(MI->getOperand(3).getReg())458.addImm(0);459break;460461case SystemZ::CLGIBCall:462LoweredMI = MCInstBuilder(SystemZ::CLGIB)463.addReg(MI->getOperand(0).getReg())464.addImm(MI->getOperand(1).getImm())465.addImm(MI->getOperand(2).getImm())466.addReg(MI->getOperand(3).getReg())467.addImm(0);468break;469470case SystemZ::TLS_GDCALL:471LoweredMI = MCInstBuilder(SystemZ::BRASL)472.addReg(SystemZ::R14D)473.addExpr(getTLSGetOffset(MF->getContext()))474.addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_TLSGD));475break;476477case SystemZ::TLS_LDCALL:478LoweredMI = MCInstBuilder(SystemZ::BRASL)479.addReg(SystemZ::R14D)480.addExpr(getTLSGetOffset(MF->getContext()))481.addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_TLSLDM));482break;483484case SystemZ::GOT:485LoweredMI = MCInstBuilder(SystemZ::LARL)486.addReg(MI->getOperand(0).getReg())487.addExpr(getGlobalOffsetTable(MF->getContext()));488break;489490case SystemZ::IILF64:491LoweredMI = MCInstBuilder(SystemZ::IILF)492.addReg(SystemZMC::getRegAsGR32(MI->getOperand(0).getReg()))493.addImm(MI->getOperand(2).getImm());494break;495496case SystemZ::IIHF64:497LoweredMI = MCInstBuilder(SystemZ::IIHF)498.addReg(SystemZMC::getRegAsGRH32(MI->getOperand(0).getReg()))499.addImm(MI->getOperand(2).getImm());500break;501502case SystemZ::RISBHH:503case SystemZ::RISBHL:504LoweredMI = lowerRIEfLow(MI, SystemZ::RISBHG);505break;506507case SystemZ::RISBLH:508case SystemZ::RISBLL:509LoweredMI = lowerRIEfLow(MI, SystemZ::RISBLG);510break;511512case SystemZ::VLVGP32:513LoweredMI = MCInstBuilder(SystemZ::VLVGP)514.addReg(MI->getOperand(0).getReg())515.addReg(SystemZMC::getRegAsGR64(MI->getOperand(1).getReg()))516.addReg(SystemZMC::getRegAsGR64(MI->getOperand(2).getReg()));517break;518519case SystemZ::VLR32:520case SystemZ::VLR64:521LoweredMI = MCInstBuilder(SystemZ::VLR)522.addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg()))523.addReg(SystemZMC::getRegAsVR128(MI->getOperand(1).getReg()));524break;525526case SystemZ::VL:527Lower.lower(MI, LoweredMI);528lowerAlignmentHint(MI, LoweredMI, SystemZ::VLAlign);529break;530531case SystemZ::VST:532Lower.lower(MI, LoweredMI);533lowerAlignmentHint(MI, LoweredMI, SystemZ::VSTAlign);534break;535536case SystemZ::VLM:537Lower.lower(MI, LoweredMI);538lowerAlignmentHint(MI, LoweredMI, SystemZ::VLMAlign);539break;540541case SystemZ::VSTM:542Lower.lower(MI, LoweredMI);543lowerAlignmentHint(MI, LoweredMI, SystemZ::VSTMAlign);544break;545546case SystemZ::VL32:547LoweredMI = lowerSubvectorLoad(MI, SystemZ::VLREPF);548break;549550case SystemZ::VL64:551LoweredMI = lowerSubvectorLoad(MI, SystemZ::VLREPG);552break;553554case SystemZ::VST32:555LoweredMI = lowerSubvectorStore(MI, SystemZ::VSTEF);556break;557558case SystemZ::VST64:559LoweredMI = lowerSubvectorStore(MI, SystemZ::VSTEG);560break;561562case SystemZ::LFER:563LoweredMI = MCInstBuilder(SystemZ::VLGVF)564.addReg(SystemZMC::getRegAsGR64(MI->getOperand(0).getReg()))565.addReg(SystemZMC::getRegAsVR128(MI->getOperand(1).getReg()))566.addReg(0).addImm(0);567break;568569case SystemZ::LEFR:570LoweredMI = MCInstBuilder(SystemZ::VLVGF)571.addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg()))572.addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg()))573.addReg(MI->getOperand(1).getReg())574.addReg(0).addImm(0);575break;576577#define LOWER_LOW(NAME) \578case SystemZ::NAME##64: LoweredMI = lowerRILow(MI, SystemZ::NAME); break579580LOWER_LOW(IILL);581LOWER_LOW(IILH);582LOWER_LOW(TMLL);583LOWER_LOW(TMLH);584LOWER_LOW(NILL);585LOWER_LOW(NILH);586LOWER_LOW(NILF);587LOWER_LOW(OILL);588LOWER_LOW(OILH);589LOWER_LOW(OILF);590LOWER_LOW(XILF);591592#undef LOWER_LOW593594#define LOWER_HIGH(NAME) \595case SystemZ::NAME##64: LoweredMI = lowerRIHigh(MI, SystemZ::NAME); break596597LOWER_HIGH(IIHL);598LOWER_HIGH(IIHH);599LOWER_HIGH(TMHL);600LOWER_HIGH(TMHH);601LOWER_HIGH(NIHL);602LOWER_HIGH(NIHH);603LOWER_HIGH(NIHF);604LOWER_HIGH(OIHL);605LOWER_HIGH(OIHH);606LOWER_HIGH(OIHF);607LOWER_HIGH(XIHF);608609#undef LOWER_HIGH610611case SystemZ::Serialize:612if (MF->getSubtarget<SystemZSubtarget>().hasFastSerialization())613LoweredMI = MCInstBuilder(SystemZ::BCRAsm)614.addImm(14).addReg(SystemZ::R0D);615else616LoweredMI = MCInstBuilder(SystemZ::BCRAsm)617.addImm(15).addReg(SystemZ::R0D);618break;619620// We want to emit "j .+2" for traps, jumping to the relative immediate field621// of the jump instruction, which is an illegal instruction. We cannot emit a622// "." symbol, so create and emit a temp label before the instruction and use623// that instead.624case SystemZ::Trap: {625MCSymbol *DotSym = OutContext.createTempSymbol();626OutStreamer->emitLabel(DotSym);627628const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(DotSym, OutContext);629const MCConstantExpr *ConstExpr = MCConstantExpr::create(2, OutContext);630LoweredMI = MCInstBuilder(SystemZ::J)631.addExpr(MCBinaryExpr::createAdd(Expr, ConstExpr, OutContext));632}633break;634635// Conditional traps will create a branch on condition instruction that jumps636// to the relative immediate field of the jump instruction. (eg. "jo .+2")637case SystemZ::CondTrap: {638MCSymbol *DotSym = OutContext.createTempSymbol();639OutStreamer->emitLabel(DotSym);640641const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(DotSym, OutContext);642const MCConstantExpr *ConstExpr = MCConstantExpr::create(2, OutContext);643LoweredMI = MCInstBuilder(SystemZ::BRC)644.addImm(MI->getOperand(0).getImm())645.addImm(MI->getOperand(1).getImm())646.addExpr(MCBinaryExpr::createAdd(Expr, ConstExpr, OutContext));647}648break;649650case TargetOpcode::FENTRY_CALL:651LowerFENTRY_CALL(*MI, Lower);652return;653654case TargetOpcode::STACKMAP:655LowerSTACKMAP(*MI);656return;657658case TargetOpcode::PATCHPOINT:659LowerPATCHPOINT(*MI, Lower);660return;661662case SystemZ::EXRL_Pseudo: {663unsigned TargetInsOpc = MI->getOperand(0).getImm();664Register LenMinus1Reg = MI->getOperand(1).getReg();665Register DestReg = MI->getOperand(2).getReg();666int64_t DestDisp = MI->getOperand(3).getImm();667Register SrcReg = MI->getOperand(4).getReg();668int64_t SrcDisp = MI->getOperand(5).getImm();669670SystemZTargetStreamer *TS = getTargetStreamer();671MCSymbol *DotSym = nullptr;672MCInst ET = MCInstBuilder(TargetInsOpc).addReg(DestReg)673.addImm(DestDisp).addImm(1).addReg(SrcReg).addImm(SrcDisp);674SystemZTargetStreamer::MCInstSTIPair ET_STI(ET, &MF->getSubtarget());675SystemZTargetStreamer::EXRLT2SymMap::iterator I =676TS->EXRLTargets2Sym.find(ET_STI);677if (I != TS->EXRLTargets2Sym.end())678DotSym = I->second;679else680TS->EXRLTargets2Sym[ET_STI] = DotSym = OutContext.createTempSymbol();681const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);682EmitToStreamer(683*OutStreamer,684MCInstBuilder(SystemZ::EXRL).addReg(LenMinus1Reg).addExpr(Dot));685return;686}687688default:689Lower.lower(MI, LoweredMI);690break;691}692EmitToStreamer(*OutStreamer, LoweredMI);693}694695// Emit the largest nop instruction smaller than or equal to NumBytes696// bytes. Return the size of nop emitted.697static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,698unsigned NumBytes, const MCSubtargetInfo &STI) {699if (NumBytes < 2) {700llvm_unreachable("Zero nops?");701return 0;702}703else if (NumBytes < 4) {704OutStreamer.emitInstruction(705MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI);706return 2;707}708else if (NumBytes < 6) {709OutStreamer.emitInstruction(710MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0),711STI);712return 4;713}714else {715MCSymbol *DotSym = OutContext.createTempSymbol();716const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);717OutStreamer.emitLabel(DotSym);718OutStreamer.emitInstruction(719MCInstBuilder(SystemZ::BRCLAsm).addImm(0).addExpr(Dot), STI);720return 6;721}722}723724void SystemZAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI,725SystemZMCInstLower &Lower) {726MCContext &Ctx = MF->getContext();727if (MF->getFunction().hasFnAttribute("mrecord-mcount")) {728MCSymbol *DotSym = OutContext.createTempSymbol();729OutStreamer->pushSection();730OutStreamer->switchSection(731Ctx.getELFSection("__mcount_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));732OutStreamer->emitSymbolValue(DotSym, 8);733OutStreamer->popSection();734OutStreamer->emitLabel(DotSym);735}736737if (MF->getFunction().hasFnAttribute("mnop-mcount")) {738EmitNop(Ctx, *OutStreamer, 6, getSubtargetInfo());739return;740}741742MCSymbol *fentry = Ctx.getOrCreateSymbol("__fentry__");743const MCSymbolRefExpr *Op =744MCSymbolRefExpr::create(fentry, MCSymbolRefExpr::VK_PLT, Ctx);745OutStreamer->emitInstruction(746MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R0D).addExpr(Op),747getSubtargetInfo());748}749750void SystemZAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {751auto *TII = MF->getSubtarget<SystemZSubtarget>().getInstrInfo();752753unsigned NumNOPBytes = MI.getOperand(1).getImm();754755auto &Ctx = OutStreamer->getContext();756MCSymbol *MILabel = Ctx.createTempSymbol();757OutStreamer->emitLabel(MILabel);758759SM.recordStackMap(*MILabel, MI);760assert(NumNOPBytes % 2 == 0 && "Invalid number of NOP bytes requested!");761762// Scan ahead to trim the shadow.763unsigned ShadowBytes = 0;764const MachineBasicBlock &MBB = *MI.getParent();765MachineBasicBlock::const_iterator MII(MI);766++MII;767while (ShadowBytes < NumNOPBytes) {768if (MII == MBB.end() ||769MII->getOpcode() == TargetOpcode::PATCHPOINT ||770MII->getOpcode() == TargetOpcode::STACKMAP)771break;772ShadowBytes += TII->getInstSizeInBytes(*MII);773if (MII->isCall())774break;775++MII;776}777778// Emit nops.779while (ShadowBytes < NumNOPBytes)780ShadowBytes += EmitNop(OutContext, *OutStreamer, NumNOPBytes - ShadowBytes,781getSubtargetInfo());782}783784// Lower a patchpoint of the form:785// [<def>], <id>, <numBytes>, <target>, <numArgs>786void SystemZAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,787SystemZMCInstLower &Lower) {788auto &Ctx = OutStreamer->getContext();789MCSymbol *MILabel = Ctx.createTempSymbol();790OutStreamer->emitLabel(MILabel);791792SM.recordPatchPoint(*MILabel, MI);793PatchPointOpers Opers(&MI);794795unsigned EncodedBytes = 0;796const MachineOperand &CalleeMO = Opers.getCallTarget();797798if (CalleeMO.isImm()) {799uint64_t CallTarget = CalleeMO.getImm();800if (CallTarget) {801unsigned ScratchIdx = -1;802unsigned ScratchReg = 0;803do {804ScratchIdx = Opers.getNextScratchIdx(ScratchIdx + 1);805ScratchReg = MI.getOperand(ScratchIdx).getReg();806} while (ScratchReg == SystemZ::R0D);807808// Materialize the call target address809EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF)810.addReg(ScratchReg)811.addImm(CallTarget & 0xFFFFFFFF));812EncodedBytes += 6;813if (CallTarget >> 32) {814EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF)815.addReg(ScratchReg)816.addImm(CallTarget >> 32));817EncodedBytes += 6;818}819820EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)821.addReg(SystemZ::R14D)822.addReg(ScratchReg));823EncodedBytes += 2;824}825} else if (CalleeMO.isGlobal()) {826const MCExpr *Expr = Lower.getExpr(CalleeMO, MCSymbolRefExpr::VK_PLT);827EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)828.addReg(SystemZ::R14D)829.addExpr(Expr));830EncodedBytes += 6;831}832833// Emit padding.834unsigned NumBytes = Opers.getNumPatchBytes();835assert(NumBytes >= EncodedBytes &&836"Patchpoint can't request size less than the length of a call.");837assert((NumBytes - EncodedBytes) % 2 == 0 &&838"Invalid number of NOP bytes requested!");839while (EncodedBytes < NumBytes)840EncodedBytes += EmitNop(OutContext, *OutStreamer, NumBytes - EncodedBytes,841getSubtargetInfo());842}843844// The *alignment* of 128-bit vector types is different between the software845// and hardware vector ABIs. If the there is an externally visible use of a846// vector type in the module it should be annotated with an attribute.847void SystemZAsmPrinter::emitAttributes(Module &M) {848if (M.getModuleFlag("s390x-visible-vector-ABI")) {849bool HasVectorFeature =850TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureVector);851OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1);852}853}854855// Convert a SystemZ-specific constant pool modifier into the associated856// MCSymbolRefExpr variant kind.857static MCSymbolRefExpr::VariantKind858getModifierVariantKind(SystemZCP::SystemZCPModifier Modifier) {859switch (Modifier) {860case SystemZCP::TLSGD: return MCSymbolRefExpr::VK_TLSGD;861case SystemZCP::TLSLDM: return MCSymbolRefExpr::VK_TLSLDM;862case SystemZCP::DTPOFF: return MCSymbolRefExpr::VK_DTPOFF;863case SystemZCP::NTPOFF: return MCSymbolRefExpr::VK_NTPOFF;864}865llvm_unreachable("Invalid SystemCPModifier!");866}867868void SystemZAsmPrinter::emitMachineConstantPoolValue(869MachineConstantPoolValue *MCPV) {870auto *ZCPV = static_cast<SystemZConstantPoolValue*>(MCPV);871872const MCExpr *Expr =873MCSymbolRefExpr::create(getSymbol(ZCPV->getGlobalValue()),874getModifierVariantKind(ZCPV->getModifier()),875OutContext);876uint64_t Size = getDataLayout().getTypeAllocSize(ZCPV->getType());877878OutStreamer->emitValue(Expr, Size);879}880881static void printFormattedRegName(const MCAsmInfo *MAI, unsigned RegNo,882raw_ostream &OS) {883const char *RegName = SystemZInstPrinter::getRegisterName(RegNo);884if (MAI->getAssemblerDialect() == AD_HLASM) {885// Skip register prefix so that only register number is left886assert(isalpha(RegName[0]) && isdigit(RegName[1]));887OS << (RegName + 1);888} else889OS << '%' << RegName;890}891892static void printReg(unsigned Reg, const MCAsmInfo *MAI, raw_ostream &OS) {893if (!Reg)894OS << '0';895else896printFormattedRegName(MAI, Reg, OS);897}898899static void printOperand(const MCOperand &MCOp, const MCAsmInfo *MAI,900raw_ostream &OS) {901if (MCOp.isReg())902printReg(MCOp.getReg(), MAI, OS);903else if (MCOp.isImm())904OS << MCOp.getImm();905else if (MCOp.isExpr())906MCOp.getExpr()->print(OS, MAI);907else908llvm_unreachable("Invalid operand");909}910911static void printAddress(const MCAsmInfo *MAI, unsigned Base,912const MCOperand &DispMO, unsigned Index,913raw_ostream &OS) {914printOperand(DispMO, MAI, OS);915if (Base || Index) {916OS << '(';917if (Index) {918printFormattedRegName(MAI, Index, OS);919if (Base)920OS << ',';921}922if (Base)923printFormattedRegName(MAI, Base, OS);924OS << ')';925}926}927928bool SystemZAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,929const char *ExtraCode,930raw_ostream &OS) {931const MCRegisterInfo &MRI = *TM.getMCRegisterInfo();932const MachineOperand &MO = MI->getOperand(OpNo);933MCOperand MCOp;934if (ExtraCode) {935if (ExtraCode[0] == 'N' && !ExtraCode[1] && MO.isReg() &&936SystemZ::GR128BitRegClass.contains(MO.getReg()))937MCOp =938MCOperand::createReg(MRI.getSubReg(MO.getReg(), SystemZ::subreg_l64));939else940return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS);941} else {942SystemZMCInstLower Lower(MF->getContext(), *this);943MCOp = Lower.lowerOperand(MO);944}945printOperand(MCOp, MAI, OS);946return false;947}948949bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,950unsigned OpNo,951const char *ExtraCode,952raw_ostream &OS) {953if (ExtraCode && ExtraCode[0] && !ExtraCode[1]) {954switch (ExtraCode[0]) {955case 'A':956// Unlike EmitMachineNode(), EmitSpecialNode(INLINEASM) does not call957// setMemRefs(), so MI->memoperands() is empty and the alignment958// information is not available.959return false;960case 'O':961OS << MI->getOperand(OpNo + 1).getImm();962return false;963case 'R':964::printReg(MI->getOperand(OpNo).getReg(), MAI, OS);965return false;966}967}968printAddress(MAI, MI->getOperand(OpNo).getReg(),969MCOperand::createImm(MI->getOperand(OpNo + 1).getImm()),970MI->getOperand(OpNo + 2).getReg(), OS);971return false;972}973974void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {975auto TT = OutContext.getTargetTriple();976if (TT.isOSzOS()) {977emitADASection();978emitIDRLSection(M);979}980emitAttributes(M);981}982983void SystemZAsmPrinter::emitADASection() {984OutStreamer->pushSection();985986const unsigned PointerSize = getDataLayout().getPointerSize();987OutStreamer->switchSection(getObjFileLowering().getADASection());988989unsigned EmittedBytes = 0;990for (auto &Entry : ADATable.getTable()) {991const MCSymbol *Sym;992unsigned SlotKind;993std::tie(Sym, SlotKind) = Entry.first;994unsigned Offset = Entry.second;995assert(Offset == EmittedBytes && "Offset not as expected");996(void)EmittedBytes;997#define EMIT_COMMENT(Str) \998OutStreamer->AddComment(Twine("Offset ") \999.concat(utostr(Offset)) \1000.concat(" " Str " ") \1001.concat(Sym->getName()));1002switch (SlotKind) {1003case SystemZII::MO_ADA_DIRECT_FUNC_DESC:1004// Language Environment DLL logic requires function descriptors, for1005// imported functions, that are placed in the ADA to be 8 byte aligned.1006EMIT_COMMENT("function descriptor of");1007OutStreamer->emitValue(1008SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_RCon,1009MCSymbolRefExpr::create(Sym, OutContext),1010OutContext),1011PointerSize);1012OutStreamer->emitValue(1013SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,1014MCSymbolRefExpr::create(Sym, OutContext),1015OutContext),1016PointerSize);1017EmittedBytes += PointerSize * 2;1018break;1019case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:1020EMIT_COMMENT("pointer to data symbol");1021OutStreamer->emitValue(1022SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_None,1023MCSymbolRefExpr::create(Sym, OutContext),1024OutContext),1025PointerSize);1026EmittedBytes += PointerSize;1027break;1028case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {1029MCSymbol *Alias = OutContext.createTempSymbol(1030Twine(Sym->getName()).concat("@indirect"));1031OutStreamer->emitAssignment(Alias,1032MCSymbolRefExpr::create(Sym, OutContext));1033OutStreamer->emitSymbolAttribute(Alias, MCSA_IndirectSymbol);10341035EMIT_COMMENT("pointer to function descriptor");1036OutStreamer->emitValue(1037SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,1038MCSymbolRefExpr::create(Alias, OutContext),1039OutContext),1040PointerSize);1041EmittedBytes += PointerSize;1042break;1043}1044default:1045llvm_unreachable("Unexpected slot kind");1046}1047#undef EMIT_COMMENT1048}1049OutStreamer->popSection();1050}10511052static std::string getProductID(Module &M) {1053std::string ProductID;1054if (auto *MD = M.getModuleFlag("zos_product_id"))1055ProductID = cast<MDString>(MD)->getString().str();1056if (ProductID.empty())1057ProductID = "LLVM";1058return ProductID;1059}10601061static uint32_t getProductVersion(Module &M) {1062if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>(1063M.getModuleFlag("zos_product_major_version")))1064return VersionVal->getZExtValue();1065return LLVM_VERSION_MAJOR;1066}10671068static uint32_t getProductRelease(Module &M) {1069if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>(1070M.getModuleFlag("zos_product_minor_version")))1071return ReleaseVal->getZExtValue();1072return LLVM_VERSION_MINOR;1073}10741075static uint32_t getProductPatch(Module &M) {1076if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>(1077M.getModuleFlag("zos_product_patchlevel")))1078return PatchVal->getZExtValue();1079return LLVM_VERSION_PATCH;1080}10811082static time_t getTranslationTime(Module &M) {1083std::time_t Time = 0;1084if (auto *Val = mdconst::extract_or_null<ConstantInt>(1085M.getModuleFlag("zos_translation_time"))) {1086long SecondsSinceEpoch = Val->getSExtValue();1087Time = static_cast<time_t>(SecondsSinceEpoch);1088}1089return Time;1090}10911092void SystemZAsmPrinter::emitIDRLSection(Module &M) {1093OutStreamer->pushSection();1094OutStreamer->switchSection(getObjFileLowering().getIDRLSection());1095constexpr unsigned IDRLDataLength = 30;1096std::time_t Time = getTranslationTime(M);10971098uint32_t ProductVersion = getProductVersion(M);1099uint32_t ProductRelease = getProductRelease(M);11001101std::string ProductID = getProductID(M);11021103SmallString<IDRLDataLength + 1> TempStr;1104raw_svector_ostream O(TempStr);1105O << formatv("{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}",1106ProductID.substr(0, 10).c_str(), ProductVersion, ProductRelease,1107llvm::sys::toUtcTime(Time), "0");1108SmallString<IDRLDataLength> Data;1109ConverterEBCDIC::convertToEBCDIC(TempStr, Data);11101111OutStreamer->emitInt8(0); // Reserved.1112OutStreamer->emitInt8(3); // Format.1113OutStreamer->emitInt16(IDRLDataLength); // Length.1114OutStreamer->emitBytes(Data.str());1115OutStreamer->popSection();1116}11171118void SystemZAsmPrinter::emitFunctionBodyEnd() {1119if (TM.getTargetTriple().isOSzOS()) {1120// Emit symbol for the end of function if the z/OS target streamer1121// is used. This is needed to calculate the size of the function.1122MCSymbol *FnEndSym = createTempSymbol("func_end");1123OutStreamer->emitLabel(FnEndSym);11241125OutStreamer->pushSection();1126OutStreamer->switchSection(getObjFileLowering().getPPA1Section());1127emitPPA1(FnEndSym);1128OutStreamer->popSection();11291130CurrentFnPPA1Sym = nullptr;1131CurrentFnEPMarkerSym = nullptr;1132}1133}11341135static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,1136bool StackProtector, bool FPRMask, bool VRMask,1137bool EHBlock, bool HasName) {1138enum class PPA1Flag1 : uint8_t {1139DSA64Bit = (0x80 >> 0),1140VarArg = (0x80 >> 7),1141LLVM_MARK_AS_BITMASK_ENUM(DSA64Bit)1142};1143enum class PPA1Flag2 : uint8_t {1144ExternalProcedure = (0x80 >> 0),1145STACKPROTECTOR = (0x80 >> 3),1146LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure)1147};1148enum class PPA1Flag3 : uint8_t {1149FPRMask = (0x80 >> 2),1150LLVM_MARK_AS_BITMASK_ENUM(FPRMask)1151};1152enum class PPA1Flag4 : uint8_t {1153EPMOffsetPresent = (0x80 >> 0),1154VRMask = (0x80 >> 2),1155EHBlock = (0x80 >> 3),1156ProcedureNamePresent = (0x80 >> 7),1157LLVM_MARK_AS_BITMASK_ENUM(EPMOffsetPresent)1158};11591160// Declare optional section flags that can be modified.1161auto Flags1 = PPA1Flag1(0);1162auto Flags2 = PPA1Flag2::ExternalProcedure;1163auto Flags3 = PPA1Flag3(0);1164auto Flags4 = PPA1Flag4::EPMOffsetPresent;11651166Flags1 |= PPA1Flag1::DSA64Bit;11671168if (VarArg)1169Flags1 |= PPA1Flag1::VarArg;11701171if (StackProtector)1172Flags2 |= PPA1Flag2::STACKPROTECTOR;11731174// SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in.1175if (FPRMask)1176Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag.11771178if (VRMask)1179Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag.11801181if (EHBlock)1182Flags4 |= PPA1Flag4::EHBlock; // Add optional EH block.11831184if (HasName)1185Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block.11861187OutStreamer->AddComment("PPA1 Flags 1");1188if ((Flags1 & PPA1Flag1::DSA64Bit) == PPA1Flag1::DSA64Bit)1189OutStreamer->AddComment(" Bit 0: 1 = 64-bit DSA");1190else1191OutStreamer->AddComment(" Bit 0: 0 = 32-bit DSA");1192if ((Flags1 & PPA1Flag1::VarArg) == PPA1Flag1::VarArg)1193OutStreamer->AddComment(" Bit 7: 1 = Vararg function");1194OutStreamer->emitInt8(static_cast<uint8_t>(Flags1)); // Flags 1.11951196OutStreamer->AddComment("PPA1 Flags 2");1197if ((Flags2 & PPA1Flag2::ExternalProcedure) == PPA1Flag2::ExternalProcedure)1198OutStreamer->AddComment(" Bit 0: 1 = External procedure");1199if ((Flags2 & PPA1Flag2::STACKPROTECTOR) == PPA1Flag2::STACKPROTECTOR)1200OutStreamer->AddComment(" Bit 3: 1 = STACKPROTECT is enabled");1201else1202OutStreamer->AddComment(" Bit 3: 0 = STACKPROTECT is not enabled");1203OutStreamer->emitInt8(static_cast<uint8_t>(Flags2)); // Flags 2.12041205OutStreamer->AddComment("PPA1 Flags 3");1206if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask)1207OutStreamer->AddComment(" Bit 2: 1 = FP Reg Mask is in optional area");1208OutStreamer->emitInt8(1209static_cast<uint8_t>(Flags3)); // Flags 3 (optional sections).12101211OutStreamer->AddComment("PPA1 Flags 4");1212if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask)1213OutStreamer->AddComment(" Bit 2: 1 = Vector Reg Mask is in optional area");1214if ((Flags4 & PPA1Flag4::EHBlock) == PPA1Flag4::EHBlock)1215OutStreamer->AddComment(" Bit 3: 1 = C++ EH block");1216if ((Flags4 & PPA1Flag4::ProcedureNamePresent) ==1217PPA1Flag4::ProcedureNamePresent)1218OutStreamer->AddComment(" Bit 7: 1 = Name Length and Name");1219OutStreamer->emitInt8(static_cast<uint8_t>(1220Flags4)); // Flags 4 (optional sections, always emit these).1221}12221223static void emitPPA1Name(std::unique_ptr<MCStreamer> &OutStreamer,1224StringRef OutName) {1225size_t NameSize = OutName.size();1226uint16_t OutSize;1227if (NameSize < UINT16_MAX) {1228OutSize = static_cast<uint16_t>(NameSize);1229} else {1230OutName = OutName.substr(0, UINT16_MAX);1231OutSize = UINT16_MAX;1232}1233// Emit padding to ensure that the next optional field word-aligned.1234uint8_t ExtraZeros = 4 - ((2 + OutSize) % 4);12351236SmallString<512> OutnameConv;1237ConverterEBCDIC::convertToEBCDIC(OutName, OutnameConv);1238OutName = OutnameConv.str();12391240OutStreamer->AddComment("Length of Name");1241OutStreamer->emitInt16(OutSize);1242OutStreamer->AddComment("Name of Function");1243OutStreamer->emitBytes(OutName);1244OutStreamer->emitZeros(ExtraZeros);1245}12461247void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {1248assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");12491250const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();1251const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();1252const auto TargetHasVector = Subtarget.hasVector();12531254const SystemZMachineFunctionInfo *ZFI =1255MF->getInfo<SystemZMachineFunctionInfo>();1256const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>(1257Subtarget.getFrameLowering());1258const MachineFrameInfo &MFFrame = MF->getFrameInfo();12591260// Get saved GPR/FPR/VPR masks.1261const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();1262uint16_t SavedGPRMask = 0;1263uint16_t SavedFPRMask = 0;1264uint8_t SavedVRMask = 0;1265int64_t OffsetFPR = 0;1266int64_t OffsetVR = 0;1267const int64_t TopOfStack =1268MFFrame.getOffsetAdjustment() + MFFrame.getStackSize();12691270// Loop over the spilled registers. The CalleeSavedInfo can't be used because1271// it does not contain all spilled registers.1272for (unsigned I = ZFI->getSpillGPRRegs().LowGPR,1273E = ZFI->getSpillGPRRegs().HighGPR;1274I && E && I <= E; ++I) {1275unsigned V = TRI->getEncodingValue((Register)I);1276assert(V < 16 && "GPR index out of range");1277SavedGPRMask |= 1 << (15 - V);1278}12791280for (auto &CS : CSI) {1281unsigned Reg = CS.getReg();1282unsigned I = TRI->getEncodingValue(Reg);12831284if (SystemZ::FP64BitRegClass.contains(Reg)) {1285assert(I < 16 && "FPR index out of range");1286SavedFPRMask |= 1 << (15 - I);1287int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());1288if (Temp < OffsetFPR)1289OffsetFPR = Temp;1290} else if (SystemZ::VR128BitRegClass.contains(Reg)) {1291assert(I >= 16 && I <= 23 && "VPR index out of range");1292unsigned BitNum = I - 16;1293SavedVRMask |= 1 << (7 - BitNum);1294int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());1295if (Temp < OffsetVR)1296OffsetVR = Temp;1297}1298}12991300// Adjust the offset.1301OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0;1302OffsetVR += (OffsetVR < 0) ? TopOfStack : 0;13031304// Get alloca register.1305uint8_t FrameReg = TRI->getEncodingValue(TRI->getFrameRegister(*MF));1306uint8_t AllocaReg = ZFL->hasFP(*MF) ? FrameReg : 0;1307assert(AllocaReg < 16 && "Can't have alloca register larger than 15");1308(void)AllocaReg;13091310// Build FPR save area offset.1311uint32_t FrameAndFPROffset = 0;1312if (SavedFPRMask) {1313uint64_t FPRSaveAreaOffset = OffsetFPR;1314assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range");13151316FrameAndFPROffset = FPRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.1317FrameAndFPROffset |= FrameReg << 28; // Put into top 4 bits.1318}13191320// Build VR save area offset.1321uint32_t FrameAndVROffset = 0;1322if (TargetHasVector && SavedVRMask) {1323uint64_t VRSaveAreaOffset = OffsetVR;1324assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range");13251326FrameAndVROffset = VRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.1327FrameAndVROffset |= FrameReg << 28; // Put into top 4 bits.1328}13291330// Emit PPA1 section.1331OutStreamer->AddComment("PPA1");1332OutStreamer->emitLabel(CurrentFnPPA1Sym);1333OutStreamer->AddComment("Version");1334OutStreamer->emitInt8(0x02); // Version.1335OutStreamer->AddComment("LE Signature X'CE'");1336OutStreamer->emitInt8(0xCE); // CEL signature.1337OutStreamer->AddComment("Saved GPR Mask");1338OutStreamer->emitInt16(SavedGPRMask);1339OutStreamer->AddComment("Offset to PPA2");1340OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CurrentFnPPA1Sym, 4);13411342bool NeedEmitEHBlock = !MF->getLandingPads().empty();13431344bool HasName =1345MF->getFunction().hasName() && MF->getFunction().getName().size() > 0;13461347emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(),1348MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0,1349TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, HasName);13501351OutStreamer->AddComment("Length/4 of Parms");1352OutStreamer->emitInt16(1353static_cast<uint16_t>(ZFI->getSizeOfFnParams() / 4)); // Parms/4.1354OutStreamer->AddComment("Length of Code");1355OutStreamer->emitAbsoluteSymbolDiff(FnEndSym, CurrentFnEPMarkerSym, 4);13561357// Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).1358if (SavedFPRMask) {1359OutStreamer->AddComment("FPR mask");1360OutStreamer->emitInt16(SavedFPRMask);1361OutStreamer->AddComment("AR mask");1362OutStreamer->emitInt16(0); // AR Mask, unused currently.1363OutStreamer->AddComment("FPR Save Area Locator");1364OutStreamer->AddComment(Twine(" Bit 0-3: Register R")1365.concat(utostr(FrameAndFPROffset >> 28))1366.str());1367OutStreamer->AddComment(Twine(" Bit 4-31: Offset ")1368.concat(utostr(FrameAndFPROffset & 0x0FFFFFFF))1369.str());1370OutStreamer->emitInt32(FrameAndFPROffset); // Offset to FPR save area with1371// register to add value to1372// (alloca reg).1373}13741375// Emit saved VR mask to VR save area.1376if (TargetHasVector && SavedVRMask) {1377OutStreamer->AddComment("VR mask");1378OutStreamer->emitInt8(SavedVRMask);1379OutStreamer->emitInt8(0); // Reserved.1380OutStreamer->emitInt16(0); // Also reserved.1381OutStreamer->AddComment("VR Save Area Locator");1382OutStreamer->AddComment(Twine(" Bit 0-3: Register R")1383.concat(utostr(FrameAndVROffset >> 28))1384.str());1385OutStreamer->AddComment(Twine(" Bit 4-31: Offset ")1386.concat(utostr(FrameAndVROffset & 0x0FFFFFFF))1387.str());1388OutStreamer->emitInt32(FrameAndVROffset);1389}13901391// Emit C++ EH information block1392const Function *Per = nullptr;1393if (NeedEmitEHBlock) {1394Per = dyn_cast<Function>(1395MF->getFunction().getPersonalityFn()->stripPointerCasts());1396MCSymbol *PersonalityRoutine =1397Per ? MF->getTarget().getSymbol(Per) : nullptr;1398assert(PersonalityRoutine && "Missing personality routine");13991400OutStreamer->AddComment("Version");1401OutStreamer->emitInt32(1);1402OutStreamer->AddComment("Flags");1403OutStreamer->emitInt32(0); // LSDA field is a WAS offset1404OutStreamer->AddComment("Personality routine");1405OutStreamer->emitInt64(ADATable.insert(1406PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC));1407OutStreamer->AddComment("LSDA location");1408MCSymbol *GCCEH = MF->getContext().getOrCreateSymbol(1409Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));1410OutStreamer->emitInt64(1411ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR));1412}14131414// Emit name length and name optional section (0x01 of flags 4)1415if (HasName)1416emitPPA1Name(OutStreamer, MF->getFunction().getName());14171418// Emit offset to entry point optional section (0x80 of flags 4).1419OutStreamer->emitAbsoluteSymbolDiff(CurrentFnEPMarkerSym, CurrentFnPPA1Sym,14204);1421}14221423void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {1424if (TM.getTargetTriple().isOSzOS())1425emitPPA2(M);1426AsmPrinter::emitStartOfAsmFile(M);1427}14281429void SystemZAsmPrinter::emitPPA2(Module &M) {1430OutStreamer->pushSection();1431OutStreamer->switchSection(getObjFileLowering().getPPA2Section());1432MCContext &OutContext = OutStreamer->getContext();1433// Make CELQSTRT symbol.1434const char *StartSymbolName = "CELQSTRT";1435MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);14361437// Create symbol and assign to class field for use in PPA1.1438PPA2Sym = OutContext.createTempSymbol("PPA2", false);1439MCSymbol *DateVersionSym = OutContext.createTempSymbol("DVS", false);14401441std::time_t Time = getTranslationTime(M);1442SmallString<15> CompilationTime; // 14 + null1443raw_svector_ostream O(CompilationTime);1444O << formatv("{0:%Y%m%d%H%M%S}", llvm::sys::toUtcTime(Time));14451446uint32_t ProductVersion = getProductVersion(M),1447ProductRelease = getProductRelease(M),1448ProductPatch = getProductPatch(M);14491450SmallString<7> Version; // 6 + null1451raw_svector_ostream ostr(Version);1452ostr << formatv("{0,0-2:d}{1,0-2:d}{2,0-2:d}", ProductVersion, ProductRelease,1453ProductPatch);14541455// Drop 0 during conversion.1456SmallString<sizeof(CompilationTime) - 1> CompilationTimeStr;1457SmallString<sizeof(Version) - 1> VersionStr;14581459ConverterEBCDIC::convertToEBCDIC(CompilationTime, CompilationTimeStr);1460ConverterEBCDIC::convertToEBCDIC(Version, VersionStr);14611462enum class PPA2MemberId : uint8_t {1463// See z/OS Language Environment Vendor Interfaces v2r5, p.23, for1464// complete list. Only the C runtime is supported by this backend.1465LE_C_Runtime = 3,1466};1467enum class PPA2MemberSubId : uint8_t {1468// List of languages using the LE C runtime implementation.1469C = 0x00,1470CXX = 0x01,1471Swift = 0x03,1472Go = 0x60,1473LLVMBasedLang = 0xe7,1474};1475// PPA2 Flags1476enum class PPA2Flags : uint8_t {1477CompileForBinaryFloatingPoint = 0x80,1478CompiledWithXPLink = 0x01,1479CompiledUnitASCII = 0x04,1480HasServiceInfo = 0x20,1481};14821483PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang;1484if (auto *MD = M.getModuleFlag("zos_cu_language")) {1485StringRef Language = cast<MDString>(MD)->getString();1486MemberSubId = StringSwitch<PPA2MemberSubId>(Language)1487.Case("C", PPA2MemberSubId::C)1488.Case("C++", PPA2MemberSubId::CXX)1489.Case("Swift", PPA2MemberSubId::Swift)1490.Case("Go", PPA2MemberSubId::Go)1491.Default(PPA2MemberSubId::LLVMBasedLang);1492}14931494// Emit PPA2 section.1495OutStreamer->emitLabel(PPA2Sym);1496OutStreamer->emitInt8(static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime));1497OutStreamer->emitInt8(static_cast<uint8_t>(MemberSubId));1498OutStreamer->emitInt8(0x22); // Member defined, c370_plist+c370_env1499OutStreamer->emitInt8(0x04); // Control level 4 (XPLink)1500OutStreamer->emitAbsoluteSymbolDiff(CELQSTRT, PPA2Sym, 4);1501OutStreamer->emitInt32(0x00000000);1502OutStreamer->emitAbsoluteSymbolDiff(DateVersionSym, PPA2Sym, 4);1503OutStreamer->emitInt32(15040x00000000); // Offset to main entry point, always 0 (so says TR).1505uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint);1506Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink);15071508if (auto *MD = M.getModuleFlag("zos_le_char_mode")) {1509const StringRef &CharMode = cast<MDString>(MD)->getString();1510if (CharMode == "ascii") {1511Flgs |= static_cast<uint8_t>(1512PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode.1513} else if (CharMode != "ebcdic") {1514report_fatal_error(1515"Only ascii or ebcdic are valid values for zos_le_char_mode "1516"metadata");1517}1518}15191520OutStreamer->emitInt8(Flgs);1521OutStreamer->emitInt8(0x00); // Reserved.1522// No MD5 signature before timestamp.1523// No FLOAT(AFP(VOLATILE)).1524// Remaining 5 flag bits reserved.1525OutStreamer->emitInt16(0x0000); // 16 Reserved flag bits.15261527// Emit date and version section.1528OutStreamer->emitLabel(DateVersionSym);1529OutStreamer->emitBytes(CompilationTimeStr.str());1530OutStreamer->emitBytes(VersionStr.str());15311532OutStreamer->emitInt16(0x0000); // Service level string length.15331534// The binder requires that the offset to the PPA2 be emitted in a different,1535// specially-named section.1536OutStreamer->switchSection(getObjFileLowering().getPPA2ListSection());1537// Emit 8 byte alignment.1538// Emit pointer to PPA2 label.1539OutStreamer->AddComment("A(PPA2-CELQSTRT)");1540OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CELQSTRT, 8);1541OutStreamer->popSection();1542}15431544void SystemZAsmPrinter::emitFunctionEntryLabel() {1545const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();15461547if (Subtarget.getTargetTriple().isOSzOS()) {1548MCContext &OutContext = OutStreamer->getContext();15491550// Save information for later use.1551std::string N(MF->getFunction().hasName()1552? Twine(MF->getFunction().getName()).concat("_").str()1553: "");15541555CurrentFnEPMarkerSym =1556OutContext.createTempSymbol(Twine("EPM_").concat(N).str(), true);1557CurrentFnPPA1Sym =1558OutContext.createTempSymbol(Twine("PPA1_").concat(N).str(), true);15591560// EntryPoint Marker1561const MachineFrameInfo &MFFrame = MF->getFrameInfo();1562bool IsUsingAlloca = MFFrame.hasVarSizedObjects();1563uint32_t DSASize = MFFrame.getStackSize();1564bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty();15651566// Set Flags.1567uint8_t Flags = 0;1568if (IsLeaf)1569Flags |= 0x08;1570if (IsUsingAlloca)1571Flags |= 0x04;15721573// Combine into top 27 bits of DSASize and bottom 5 bits of Flags.1574uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 51575DSAAndFlags |= Flags;15761577// Emit entry point marker section.1578OutStreamer->AddComment("XPLINK Routine Layout Entry");1579OutStreamer->emitLabel(CurrentFnEPMarkerSym);1580OutStreamer->AddComment("Eyecatcher 0x00C300C500C500");1581OutStreamer->emitIntValueInHex(0x00C300C500C500, 7); // Eyecatcher.1582OutStreamer->AddComment("Mark Type C'1'");1583OutStreamer->emitInt8(0xF1); // Mark Type.1584OutStreamer->AddComment("Offset to PPA1");1585OutStreamer->emitAbsoluteSymbolDiff(CurrentFnPPA1Sym, CurrentFnEPMarkerSym,15864);1587if (OutStreamer->isVerboseAsm()) {1588OutStreamer->AddComment("DSA Size 0x" + Twine::utohexstr(DSASize));1589OutStreamer->AddComment("Entry Flags");1590if (Flags & 0x08)1591OutStreamer->AddComment(" Bit 1: 1 = Leaf function");1592else1593OutStreamer->AddComment(" Bit 1: 0 = Non-leaf function");1594if (Flags & 0x04)1595OutStreamer->AddComment(" Bit 2: 1 = Uses alloca");1596else1597OutStreamer->AddComment(" Bit 2: 0 = Does not use alloca");1598}1599OutStreamer->emitInt32(DSAAndFlags);1600}16011602AsmPrinter::emitFunctionEntryLabel();1603}16041605// Force static initialization.1606extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZAsmPrinter() {1607RegisterAsmPrinter<SystemZAsmPrinter> X(getTheSystemZTarget());1608}160916101611