1//===-- SystemZXPLINKAsmPrinter.cpp - SystemZ XPLINK asm printer ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the SystemZXPLINKAsmPrinter class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "SystemZXPLINKAsmPrinter.h"
14#include "MCTargetDesc/SystemZMCTargetDesc.h"
15#include "MCTargetDesc/SystemZTargetStreamer.h"
16#include "SystemZFrameLowering.h"
17#include "SystemZInstrInfo.h"
18#include "SystemZMCInstLower.h"
19#include "SystemZMachineFunctionInfo.h"
20#include "SystemZSubtarget.h"
21#include "SystemZTargetObjectFile.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/BinaryFormat/GOFF.h"
24#include "llvm/CodeGen/MachineFrameInfo.h"
25#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
26#include "llvm/IR/Function.h"
27#include "llvm/IR/GlobalAlias.h"
28#include "llvm/IR/GlobalObject.h"
29#include "llvm/IR/Module.h"
30#include "llvm/MC/MCExpr.h"
31#include "llvm/MC/MCInstBuilder.h"
32#include "llvm/MC/MCSymbolGOFF.h"
33#include "llvm/Support/Chrono.h"
34#include "llvm/Support/ConvertEBCDIC.h"
35#include "llvm/Support/FormatVariadic.h"
36
37using namespace llvm;
38
39SystemZXPLINKAsmPrinter::SystemZXPLINKAsmPrinter(
40 TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
41 : SystemZAsmPrinter(TM, std::move(Streamer)),
42 ADATable(TM.getPointerSize(AS: 0)) {}
43
44bool SystemZXPLINKAsmPrinter::doInitialization(Module &M) {
45 SM.reset();
46
47 // In HLASM, the only way to represent aliases is to use the
48 // extra-label-at-definition strategy. This is similar to the AIX
49 // implementation with the additional caveat that all symbol attributes must
50 // be emitted before the label is emitted.
51 // Construct an aliasing list for each GlobalObject.
52 for (const auto &Alias : M.aliases()) {
53 const GlobalObject *Aliasee = Alias.getAliaseeObject();
54 if (!Aliasee)
55 OutContext.reportError(
56 L: {}, Msg: "Alias without a base object is not yet supported on z/OS.");
57
58 bool IsFunc = isa<Function>(Val: Aliasee->stripPointerCasts());
59 if (IsFunc) {
60 if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage())
61 OutContext.reportError(L: {},
62 Msg: "Weak alias/reference not supported on z/OS");
63
64 GOAliasMap[Aliasee].push_back(Elt: &Alias);
65 } else
66 OutContext.reportError(L: {},
67 Msg: "Only aliases to functions is supported in GOFF.");
68 }
69 return AsmPrinter::doInitialization(M);
70}
71
72// The XPLINK ABI requires that a no-op encoding the call type is emitted after
73// each call to a subroutine. This information can be used by the called
74// function to determine its entry point, e.g. for generating a backtrace. The
75// call type is encoded as a register number in the bcr instruction. See
76// enumeration CallType for the possible values.
77void SystemZXPLINKAsmPrinter::emitCallInformation(CallType CT) {
78 EmitToStreamer(S&: *OutStreamer,
79 Inst: MCInstBuilder(SystemZ::BCRAsm)
80 .addImm(Val: 0)
81 .addReg(Reg: SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
82}
83
84uint32_t
85SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
86 unsigned SlotKind) {
87 auto Key = std::make_pair(x&: Sym, y&: SlotKind);
88 auto It = Displacements.find(Key);
89
90 if (It != Displacements.end())
91 return (*It).second;
92
93 // Determine length of descriptor.
94 uint32_t Length;
95 switch (SlotKind) {
96 case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
97 Length = 2 * PointerSize;
98 break;
99 default:
100 Length = PointerSize;
101 break;
102 }
103
104 uint32_t Displacement = NextDisplacement;
105 Displacements[std::make_pair(x&: Sym, y&: SlotKind)] = NextDisplacement;
106 NextDisplacement += Length;
107
108 return Displacement;
109}
110
111uint32_t SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(
112 const MachineOperand MO) {
113 MCSymbol *Sym;
114 if (MO.getType() == MachineOperand::MO_GlobalAddress) {
115 const GlobalValue *GV = MO.getGlobal();
116 Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);
117 assert(Sym && "No symbol");
118 } else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
119 const char *SymName = MO.getSymbolName();
120 Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(Name: SymName);
121 assert(Sym && "No symbol");
122 } else
123 llvm_unreachable("Unexpected operand type");
124
125 unsigned ADAslotType = MO.getTargetFlags();
126 return insert(Sym, SlotKind: ADAslotType);
127}
128
129void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
130 SystemZMCInstLower Lower(MF->getContext(), *this);
131 MCInst LoweredMI;
132
133 switch (MI->getOpcode()) {
134 case SystemZ::CallBRASL_XPLINK64:
135 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(SystemZ::BRASL)
136 .addReg(Reg: SystemZ::R7D)
137 .addExpr(Val: Lower.getExpr(MO: MI->getOperand(i: 0),
138 SystemZ::S_None)));
139 emitCallInformation(CT: CallType::BRASL7);
140 return;
141
142 case SystemZ::CallBASR_XPLINK64:
143 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(SystemZ::BASR)
144 .addReg(Reg: SystemZ::R7D)
145 .addReg(Reg: MI->getOperand(i: 0).getReg()));
146 emitCallInformation(CT: CallType::BASR76);
147 return;
148
149 case SystemZ::Return_XPLINK:
150 LoweredMI =
151 MCInstBuilder(SystemZ::B).addReg(Reg: SystemZ::R7D).addImm(Val: 2).addReg(Reg: 0);
152 break;
153
154 case SystemZ::CondReturn_XPLINK:
155 LoweredMI = MCInstBuilder(SystemZ::BC)
156 .addImm(Val: MI->getOperand(i: 0).getImm())
157 .addImm(Val: MI->getOperand(i: 1).getImm())
158 .addReg(Reg: SystemZ::R7D)
159 .addImm(Val: 2)
160 .addReg(Reg: 0);
161 break;
162
163 case SystemZ::CallBASR_STACKEXT:
164 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(SystemZ::BASR)
165 .addReg(Reg: SystemZ::R3D)
166 .addReg(Reg: MI->getOperand(i: 0).getReg()));
167 emitCallInformation(CT: CallType::BASR33);
168 return;
169
170 case SystemZ::ADA_ENTRY_VALUE:
171 case SystemZ::ADA_ENTRY: {
172 const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
173 const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
174 uint32_t Disp = ADATable.insert(MO: MI->getOperand(i: 1));
175 Register TargetReg = MI->getOperand(i: 0).getReg();
176
177 Register ADAReg = MI->getOperand(i: 2).getReg();
178 Disp += MI->getOperand(i: 3).getImm();
179 bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY;
180
181 unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG;
182 unsigned Op = TII->getOpcodeForOffset(Opcode: Op0, Offset: Disp);
183
184 Register IndexReg = 0;
185 if (!Op) {
186 if (TargetReg != ADAReg) {
187 IndexReg = TargetReg;
188 // Use TargetReg to store displacement.
189 EmitToStreamer(
190 S&: *OutStreamer,
191 Inst: MCInstBuilder(SystemZ::LLILF).addReg(Reg: TargetReg).addImm(Val: Disp));
192 } else
193 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(SystemZ::ALGFI)
194 .addReg(Reg: TargetReg)
195 .addReg(Reg: TargetReg)
196 .addImm(Val: Disp));
197 Disp = 0;
198 Op = Op0;
199 }
200 EmitToStreamer(
201 S&: *OutStreamer,
202 Inst: MCInstBuilder(Op).addReg(Reg: TargetReg).addReg(Reg: ADAReg).addImm(Val: Disp).addReg(
203 Reg: IndexReg));
204 return;
205 }
206
207 default:
208 SystemZAsmPrinter::emitInstruction(MI);
209 return;
210 }
211 EmitToStreamer(S&: *OutStreamer, Inst: LoweredMI);
212}
213
214void SystemZXPLINKAsmPrinter::emitXXStructorList(const DataLayout &DL,
215 const Constant *List,
216 bool IsCtor) {
217 assert(TM.getTargetTriple().isOSBinFormatGOFF() && "Only GOFF supported");
218
219 SmallVector<Structor, 8> Structors;
220 preprocessXXStructorList(DL, List, Structors);
221 if (Structors.empty())
222 return;
223
224 const Align Align = llvm::Align(4);
225 const TargetLoweringObjectFileGOFF &Obj =
226 static_cast<const TargetLoweringObjectFileGOFF &>(getObjFileLowering());
227 for (Structor &S : Structors) {
228 MCSectionGOFF *Section =
229 static_cast<MCSectionGOFF *>(Obj.getStaticXtorSection(Priority: S.Priority));
230 OutStreamer->switchSection(Section);
231 if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection())
232 emitAlignment(Alignment: Align);
233
234 // The priority is provided as an input to getStaticXtorSection(), and is
235 // recalculated within that function as `Prio` going to going into the
236 // PR section.
237 // This priority retrieved via the `SortKey` below is the recalculated
238 // Priority.
239 uint32_t XtorPriority = Section->getPRAttributes().SortKey;
240
241 const GlobalValue *GV = dyn_cast<GlobalValue>(Val: S.Func->stripPointerCasts());
242 assert(GV && "C++ xxtor pointer was not a GlobalValue!");
243 MCSymbolGOFF *Symbol = static_cast<MCSymbolGOFF *>(getSymbol(GV));
244
245 // @@SQINIT entry: { unsigned prio; void (*ctor)(); void (*dtor)(); }
246
247 unsigned PointerSizeInBytes = DL.getPointerSize();
248
249 auto &Ctx = OutStreamer->getContext();
250 const MCExpr *ADAFuncRefExpr;
251 unsigned SlotKind = SystemZII::MO_ADA_DIRECT_FUNC_DESC;
252
253 MCSectionGOFF *ADASection =
254 static_cast<MCSectionGOFF *>(Obj.getADASection());
255 assert(ADASection && "ADA section must exist for GOFF targets!");
256 const MCSymbol *ADASym = ADASection->getBeginSymbol();
257 assert(ADASym && "ADA symbol should already be set!");
258
259 ADAFuncRefExpr = MCBinaryExpr::createAdd(
260 LHS: MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: ADASym, Ctx&: OutContext),
261 S: SystemZ::S_QCon, Ctx&: OutContext),
262 RHS: MCConstantExpr::create(Value: ADATable.insert(Sym: Symbol, SlotKind), Ctx), Ctx);
263
264 emitInt32(Value: XtorPriority);
265 if (IsCtor) {
266 OutStreamer->emitValue(Value: ADAFuncRefExpr, Size: PointerSizeInBytes);
267 OutStreamer->emitIntValue(Value: 0, Size: PointerSizeInBytes);
268 } else {
269 OutStreamer->emitIntValue(Value: 0, Size: PointerSizeInBytes);
270 OutStreamer->emitValue(Value: ADAFuncRefExpr, Size: PointerSizeInBytes);
271 }
272 }
273}
274
275void SystemZXPLINKAsmPrinter::emitEndOfAsmFile(Module &M) {
276 auto *ZOS = getTargetStreamer();
277 emitADASection();
278 emitIDRLSection(M);
279 // On z/OS, we need to associate an external data reference with an ED
280 // symbol, for which we use the the ED of the ADA. We also need to mark the
281 // reference as being to data, otherwise we cannot bind with code generated
282 // by XL.
283 for (auto &GO : M.global_objects()) {
284 if (auto *GV = dyn_cast<GlobalVariable>(Val: &GO)) {
285 if (!GV->hasInitializer()) {
286 MCSymbol *Sym = getSymbol(GV);
287 ZOS->emitADA(Sym, Section: OutContext.getObjectFileInfo()->getADASection());
288 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeObject);
289 }
290 }
291 }
292}
293
294void SystemZXPLINKAsmPrinter::emitADASection() {
295 OutStreamer->pushSection();
296
297 const unsigned PointerSize = getDataLayout().getPointerSize();
298 OutStreamer->switchSection(Section: getObjFileLowering().getADASection());
299
300 auto *ZOS = getTargetStreamer();
301 unsigned EmittedBytes = 0;
302 for (auto &Entry : ADATable.getTable()) {
303 const MCSymbol *Sym;
304 unsigned SlotKind;
305 std::tie(args&: Sym, args&: SlotKind) = Entry.first;
306 unsigned Offset = Entry.second;
307 assert(Offset == EmittedBytes && "Offset not as expected");
308 (void)EmittedBytes;
309#define EMIT_COMMENT(Str) \
310 OutStreamer->AddComment(Twine("Offset ") \
311 .concat(utostr(Offset)) \
312 .concat(" " Str " ") \
313 .concat(Sym->getName()));
314 switch (SlotKind) {
315 case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
316 // Language Environment DLL logic requires function descriptors, for
317 // imported functions, that are placed in the ADA to be 8 byte aligned.
318 EMIT_COMMENT("function descriptor of");
319 OutStreamer->emitValue(
320 Value: MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext),
321 S: SystemZ::S_RCon, Ctx&: OutContext),
322 Size: PointerSize);
323 OutStreamer->emitValue(
324 Value: MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext),
325 S: SystemZ::S_VCon, Ctx&: OutContext),
326 Size: PointerSize);
327 EmittedBytes += PointerSize * 2;
328 break;
329 case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
330 EMIT_COMMENT("pointer to data symbol");
331 OutStreamer->emitValue(
332 Value: MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext),
333 S: SystemZ::S_None, Ctx&: OutContext),
334 Size: PointerSize);
335 EmittedBytes += PointerSize;
336 break;
337 case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
338 MCSymbol *Alias = OutContext.getOrCreateSymbol(
339 Name: Twine(Sym->getName()).concat(Suffix: "@indirect"));
340 OutStreamer->emitSymbolAttribute(Symbol: Alias, Attribute: MCSA_IndirectSymbol);
341 OutStreamer->emitSymbolAttribute(Symbol: Alias, Attribute: MCSA_ELF_TypeFunction);
342 OutStreamer->emitSymbolAttribute(Symbol: Alias, Attribute: MCSA_Global);
343 OutStreamer->emitSymbolAttribute(Symbol: Alias, Attribute: MCSA_Extern);
344 MCSymbolGOFF *GOFFSym =
345 static_cast<llvm::MCSymbolGOFF *>(const_cast<llvm::MCSymbol *>(Sym));
346 ZOS->emitExternalName(Sym: Alias, Name: GOFFSym->getExternalName());
347 EMIT_COMMENT("pointer to function descriptor");
348 OutStreamer->emitValue(
349 Value: MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: Alias, Ctx&: OutContext),
350 S: SystemZ::S_VCon, Ctx&: OutContext),
351 Size: PointerSize);
352 EmittedBytes += PointerSize;
353 break;
354 }
355 default:
356 llvm_unreachable("Unexpected slot kind");
357 }
358#undef EMIT_COMMENT
359 }
360 OutStreamer->popSection();
361}
362
363static std::string getProductID(Module &M) {
364 std::string ProductID;
365 if (auto *MD = M.getModuleFlag(Key: "zos_product_id"))
366 ProductID = cast<MDString>(Val: MD)->getString().str();
367 if (ProductID.empty())
368 ProductID = "LLVM";
369 return ProductID;
370}
371
372static uint32_t getProductVersion(Module &M) {
373 if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>(
374 MD: M.getModuleFlag(Key: "zos_product_major_version")))
375 return VersionVal->getZExtValue();
376 return LLVM_VERSION_MAJOR;
377}
378
379static uint32_t getProductRelease(Module &M) {
380 if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>(
381 MD: M.getModuleFlag(Key: "zos_product_minor_version")))
382 return ReleaseVal->getZExtValue();
383 return LLVM_VERSION_MINOR;
384}
385
386static uint32_t getProductPatch(Module &M) {
387 if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>(
388 MD: M.getModuleFlag(Key: "zos_product_patchlevel")))
389 return PatchVal->getZExtValue();
390 return LLVM_VERSION_PATCH;
391}
392
393static time_t getTranslationTime(Module &M) {
394 std::time_t Time = 0;
395 if (auto *Val = mdconst::extract_or_null<ConstantInt>(
396 MD: M.getModuleFlag(Key: "zos_translation_time"))) {
397 long SecondsSinceEpoch = Val->getSExtValue();
398 Time = static_cast<time_t>(SecondsSinceEpoch);
399 }
400 return Time;
401}
402
403void SystemZXPLINKAsmPrinter::emitIDRLSection(Module &M) {
404 OutStreamer->pushSection();
405 OutStreamer->switchSection(Section: getObjFileLowering().getIDRLSection());
406 constexpr unsigned IDRLDataLength = 30;
407 std::time_t Time = getTranslationTime(M);
408
409 uint32_t ProductVersion = getProductVersion(M);
410 uint32_t ProductRelease = getProductRelease(M);
411
412 std::string ProductID = getProductID(M);
413
414 SmallString<IDRLDataLength + 1> TempStr;
415 raw_svector_ostream O(TempStr);
416 O << formatv(Fmt: "{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}",
417 Vals: ProductID.substr(pos: 0, n: 10).c_str(), Vals&: ProductVersion, Vals&: ProductRelease,
418 Vals: llvm::sys::toUtcTime(T: Time), Vals: "0");
419 SmallString<IDRLDataLength> Data;
420 ConverterEBCDIC::convertToEBCDIC(Source: TempStr, Result&: Data);
421
422 OutStreamer->emitInt8(Value: 0); // Reserved.
423 OutStreamer->emitInt8(Value: 3); // Format.
424 OutStreamer->emitInt16(Value: IDRLDataLength); // Length.
425 OutStreamer->emitBytes(Data: Data.str());
426 OutStreamer->popSection();
427}
428
429void SystemZXPLINKAsmPrinter::emitFunctionBodyEnd() {
430 // Emit symbol for the end of function if the z/OS target streamer
431 // is used. This is needed to calculate the size of the function.
432 auto *ZOS = getTargetStreamer();
433 OutStreamer->emitLabel(Symbol: ZOS->DeferredPPA1.back().FnEnd);
434}
435
436// Determine the end of the prolog and the instructions which updates the stack
437// register, and attach symbols to those instructions.
438static void determinePrologueStackUpdateSym(MachineFunction *MF,
439 MCSymbol *&EndOfPrologSym,
440 MCSymbol *&StackUpdateSym) {
441 EndOfPrologSym = nullptr;
442 StackUpdateSym = nullptr;
443
444 // Scan the basic block for the FENCE instruction which marks the end
445 // of the prologue. We know
446 // the prologue is spread at most across the first 3 basic blocks. Also record
447 // the first instruction updating the stack pointer.
448 const SystemZSubtarget &STI = MF->getSubtarget<SystemZSubtarget>();
449 auto &Regs = STI.getSpecialRegisters<SystemZXPLINK64Registers>();
450 MachineInstr *EndOfPrologMI = nullptr;
451 MachineInstr *StackUpdateMI = nullptr;
452 unsigned BBCount = 1;
453
454 for (auto &MBB : *MF) {
455 for (auto &I : MBB) {
456 if (I.getOpcode() == SystemZ::FENCE)
457 EndOfPrologMI = &I;
458 else if (!StackUpdateMI) {
459 unsigned Opcode = I.getOpcode();
460 // TODO: We can instead emit a pseudo instruction in
461 // SystemZFrameLowering to represent a stack adjustment instruction, and
462 // check for that here, instead of having to check for multiple
463 // instructions.
464 if ((Opcode == SystemZ::AGHI || Opcode == SystemZ::AGFI) &&
465 I.getOperand(i: 0).getReg() == Regs.getStackPointerRegister())
466 StackUpdateMI = &I;
467 }
468 }
469
470 // Prologue can be a max of 3 BBs if we need to call stack extension code
471 if (EndOfPrologMI || BBCount == 3)
472 break;
473
474 ++BBCount;
475 }
476
477 // Leaf functions do not have a prologue.
478 if (EndOfPrologMI == nullptr)
479 return;
480
481#ifdef EXPENSIVE_CHECKS
482 // Check that the prolog length is valid.
483 auto *TII = STI.getInstrInfo();
484 size_t Size = 0;
485
486 for (auto &MBB : *MF) {
487 bool TerminateLoop = false;
488 for (auto &I : MBB) {
489 Size += TII->getInstSizeInBytes(I);
490 if (&I == EndOfPrologMI) {
491 TerminateLoop = true;
492 break;
493 }
494 }
495 if (TerminateLoop)
496 break;
497 }
498 if (Size > 128)
499 report_fatal_error(
500 Twine(MF->getName()).concat(": Prolog exceeds 128 bytes"));
501#endif
502
503 // Attach a temporary symbol to mark the end of the prolog.
504 EndOfPrologSym = MF->getContext().createTempSymbol(Name: "end_of_prologue");
505 EndOfPrologMI->setPostInstrSymbol(MF&: *MF, Symbol: EndOfPrologSym);
506
507 if (StackUpdateMI) {
508 StackUpdateSym = MF->getContext().createTempSymbol(Name: "stack_update");
509 StackUpdateMI->setPreInstrSymbol(MF&: *MF, Symbol: StackUpdateSym);
510 }
511}
512
513void SystemZXPLINKAsmPrinter::calculatePPA1() {
514 auto *ZOS = getTargetStreamer();
515 assert(ZOS->PPA2Sym != nullptr && "PPA2 Symbol not defined");
516
517 SystemZTargetzOSStreamer::PPA1Info Info;
518
519 const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
520 const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
521
522 const SystemZMachineFunctionInfo *ZFI =
523 MF->getInfo<SystemZMachineFunctionInfo>();
524 const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>(
525 Subtarget.getFrameLowering());
526 const MachineFrameInfo &MFFrame = MF->getFrameInfo();
527
528 // Get saved GPR/FPR/VPR masks.
529 const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
530 uint16_t SavedGPRMask = 0;
531 uint16_t SavedFPRMask = 0;
532 uint8_t SavedVRMask = 0;
533 int64_t OffsetFPR = 0;
534 int64_t OffsetVR = 0;
535 const int64_t TopOfStack =
536 MFFrame.getOffsetAdjustment() + MFFrame.getStackSize();
537
538 // Loop over the spilled registers. The CalleeSavedInfo can't be used because
539 // it does not contain all spilled registers.
540 for (unsigned I = ZFI->getSpillGPRRegs().LowGPR,
541 E = ZFI->getSpillGPRRegs().HighGPR;
542 I && E && I <= E; ++I) {
543 unsigned V = TRI->getEncodingValue(Reg: (Register)I);
544 assert(V < 16 && "GPR index out of range");
545 SavedGPRMask |= 1 << (15 - V);
546 }
547
548 for (auto &CS : CSI) {
549 unsigned Reg = CS.getReg();
550 unsigned I = TRI->getEncodingValue(Reg);
551
552 if (SystemZ::FP64BitRegClass.contains(Reg)) {
553 assert(I < 16 && "FPR index out of range");
554 SavedFPRMask |= 1 << (15 - I);
555 int64_t Temp = MFFrame.getObjectOffset(ObjectIdx: CS.getFrameIdx());
556 if (Temp < OffsetFPR)
557 OffsetFPR = Temp;
558 } else if (SystemZ::VR128BitRegClass.contains(Reg)) {
559 assert(I >= 16 && I <= 23 && "VPR index out of range");
560 unsigned BitNum = I - 16;
561 SavedVRMask |= 1 << (7 - BitNum);
562 int64_t Temp = MFFrame.getObjectOffset(ObjectIdx: CS.getFrameIdx());
563 if (Temp < OffsetVR)
564 OffsetVR = Temp;
565 }
566 }
567
568 // Adjust the offset.
569 OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0;
570 OffsetVR += (OffsetVR < 0) ? TopOfStack : 0;
571
572 // Get alloca register.
573 uint8_t FrameReg = TRI->getEncodingValue(Reg: TRI->getFrameRegister(MF: *MF));
574 uint8_t AllocaReg = ZFL->hasFP(MF: *MF) ? FrameReg : 0;
575 assert(AllocaReg < 16 && "Can't have alloca register larger than 15");
576
577 MCSymbol *PersonalityRoutine = nullptr;
578 MCSymbol *GCCEH = nullptr;
579 uint64_t PersonalityADADisp = 0;
580 uint64_t GCCEHADADisp = 0;
581 if (!MF->getLandingPads().empty()) {
582 const Function *Per = dyn_cast<Function>(
583 Val: MF->getFunction().getPersonalityFn()->stripPointerCasts());
584 PersonalityRoutine = Per ? MF->getTarget().getSymbol(GV: Per) : nullptr;
585 if (PersonalityRoutine) {
586 GCCEH = MF->getContext().getOrCreateSymbol(
587 Name: Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));
588 PersonalityADADisp = ADATable.insert(
589 Sym: PersonalityRoutine, SlotKind: SystemZII::MO_ADA_INDIRECT_FUNC_DESC);
590 GCCEHADADisp = ADATable.insert(Sym: GCCEH, SlotKind: SystemZII::MO_ADA_DATA_SYMBOL_ADDR);
591 }
592 }
593
594 // Get the name of the function, with suffix _.
595 std::string N(MF->getFunction().hasName()
596 ? Twine(MF->getFunction().getName()).concat(Suffix: "_").str()
597 : "");
598
599 // Calculate the lables for the prolog size and the stack update symbol.
600 MCSymbol *EndOfPrologSym;
601 MCSymbol *StackUpdateSym;
602 determinePrologueStackUpdateSym(MF, EndOfPrologSym, StackUpdateSym);
603
604 // Save the calculated values.
605 if (MF->getFunction().hasFnAttribute(Kind: "zos-ppa1-name"))
606 Info.Name =
607 MF->getFunction().getFnAttribute(Kind: "zos-ppa1-name").getValueAsString();
608 else if (MF->getFunction().hasName())
609 Info.Name = MF->getFunction().getName();
610
611 Info.PPA1 = OutContext.createTempSymbol(Name: Twine("PPA1_").concat(Suffix: N), AlwaysAddSuffix: true);
612 Info.EPMarker = OutContext.createTempSymbol(Name: Twine("EPM_").concat(Suffix: N), AlwaysAddSuffix: true);
613 Info.FnEnd = OutContext.createTempSymbol(Name: Twine(N).concat(Suffix: "end_"));
614 Info.Fn = CurrentFnSym;
615 Info.EndOfProlog = EndOfPrologSym;
616 Info.StackUpdate = StackUpdateSym;
617 Info.PersonalityADADisp = PersonalityADADisp;
618 Info.GCCEHADADisp = GCCEHADADisp;
619 Info.OffsetFPR = OffsetFPR;
620 Info.OffsetVR = OffsetVR;
621 Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
622 Info.SizeOfFnParams = ZFI->getSizeOfFnParams();
623 Info.SavedGPRMask = SavedGPRMask;
624 Info.SavedFPRMask = SavedFPRMask;
625 Info.SavedVRMask = SavedVRMask;
626 Info.FrameReg = FrameReg;
627 Info.AllocaReg = AllocaReg;
628 Info.IsVarArg = MF->getFunction().isVarArg();
629 Info.HasStackProtector = MFFrame.hasStackProtectorIndex();
630
631 ZOS->DeferredPPA1.push_back(Elt: Info);
632}
633
634void SystemZXPLINKAsmPrinter::emitStartOfAsmFile(Module &M) {
635 emitPPA2(M);
636 AsmPrinter::emitStartOfAsmFile(M);
637}
638
639void SystemZXPLINKAsmPrinter::emitPPA2(Module &M) {
640 auto *ZOS = getTargetStreamer();
641 OutStreamer->pushSection();
642 OutStreamer->switchSection(Section: getObjFileLowering().getTextSection());
643 MCContext &OutContext = OutStreamer->getContext();
644 // Make CELQSTRT symbol.
645 const char *StartSymbolName = "CELQSTRT";
646 MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(Name: StartSymbolName);
647 OutStreamer->emitSymbolAttribute(Symbol: CELQSTRT, Attribute: MCSA_OSLinkage);
648 OutStreamer->emitSymbolAttribute(Symbol: CELQSTRT, Attribute: MCSA_Global);
649
650 // Create symbol and assign to streamer field for use in PPA1.
651 ZOS->PPA2Sym = OutContext.createTempSymbol(Name: "PPA2", AlwaysAddSuffix: false);
652 MCSymbol *PPA2Sym = ZOS->PPA2Sym;
653 MCSymbol *DateVersionSym = OutContext.createTempSymbol(Name: "DVS", AlwaysAddSuffix: false);
654
655 std::time_t Time = getTranslationTime(M);
656 SmallString<14> CompilationTimeEBCDIC, CompilationTime;
657 CompilationTime = formatv(Fmt: "{0:%Y%m%d%H%M%S}", Vals: llvm::sys::toUtcTime(T: Time));
658
659 uint32_t ProductVersion = getProductVersion(M),
660 ProductRelease = getProductRelease(M),
661 ProductPatch = getProductPatch(M);
662
663 SmallString<6> VersionEBCDIC, Version;
664 Version = formatv(Fmt: "{0,0-2:d}{1,0-2:d}{2,0-2:d}", Vals&: ProductVersion,
665 Vals&: ProductRelease, Vals&: ProductPatch);
666
667 ConverterEBCDIC::convertToEBCDIC(Source: CompilationTime, Result&: CompilationTimeEBCDIC);
668 ConverterEBCDIC::convertToEBCDIC(Source: Version, Result&: VersionEBCDIC);
669
670 enum class PPA2MemberId : uint8_t {
671 // See z/OS Language Environment Vendor Interfaces v2r5, p.23, for
672 // complete list. Only the C runtime is supported by this backend.
673 LE_C_Runtime = 3,
674 };
675 enum class PPA2MemberSubId : uint8_t {
676 // List of languages using the LE C runtime implementation.
677 C = 0x00,
678 CXX = 0x01,
679 Swift = 0x03,
680 Go = 0x60,
681 LLVMBasedLang = 0xe7,
682 };
683 // PPA2 Flags
684 enum class PPA2Flags : uint8_t {
685 CompileForBinaryFloatingPoint = 0x80,
686 CompiledWithXPLink = 0x01,
687 CompiledUnitASCII = 0x04,
688 HasServiceInfo = 0x20,
689 };
690
691 PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang;
692 if (auto *MD = M.getModuleFlag(Key: "zos_cu_language")) {
693 StringRef Language = cast<MDString>(Val: MD)->getString();
694 MemberSubId = StringSwitch<PPA2MemberSubId>(Language)
695 .Case(S: "C", Value: PPA2MemberSubId::C)
696 .Case(S: "C++", Value: PPA2MemberSubId::CXX)
697 .Case(S: "Swift", Value: PPA2MemberSubId::Swift)
698 .Case(S: "Go", Value: PPA2MemberSubId::Go)
699 .Default(Value: PPA2MemberSubId::LLVMBasedLang);
700 }
701
702 // Emit PPA2 section.
703 OutStreamer->emitLabel(Symbol: PPA2Sym);
704 OutStreamer->emitInt8(Value: static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime));
705 OutStreamer->emitInt8(Value: static_cast<uint8_t>(MemberSubId));
706 OutStreamer->emitInt8(Value: 0x22); // Member defined, c370_plist+c370_env
707 OutStreamer->emitInt8(Value: 0x04); // Control level 4 (XPLink)
708 OutStreamer->emitAbsoluteSymbolDiff(Hi: CELQSTRT, Lo: PPA2Sym, Size: 4);
709 OutStreamer->emitInt32(Value: 0x00000000);
710 OutStreamer->emitAbsoluteSymbolDiff(Hi: DateVersionSym, Lo: PPA2Sym, Size: 4);
711 OutStreamer->emitInt32(
712 Value: 0x00000000); // Offset to main entry point, always 0 (so says TR).
713 uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint);
714 Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink);
715
716 bool IsASCII = true;
717 if (auto *MD = M.getModuleFlag(Key: "zos_le_char_mode")) {
718 const StringRef &CharMode = cast<MDString>(Val: MD)->getString();
719 if (CharMode == "ebcdic")
720 IsASCII = false;
721 else if (CharMode != "ascii")
722 OutContext.reportError(
723 L: {}, Msg: "Only ascii or ebcdic are allowed for zos_le_char_mode");
724 }
725 if (IsASCII)
726 Flgs |= static_cast<uint8_t>(
727 PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode.
728
729 OutStreamer->emitInt8(Value: Flgs);
730 OutStreamer->emitInt8(Value: 0x00); // Reserved.
731 // No MD5 signature before timestamp.
732 // No FLOAT(AFP(VOLATILE)).
733 // Remaining 5 flag bits reserved.
734 OutStreamer->emitInt16(Value: 0x0000); // 16 Reserved flag bits.
735
736 // Emit date and version section.
737 OutStreamer->emitLabel(Symbol: DateVersionSym);
738 OutStreamer->emitBytes(Data: CompilationTimeEBCDIC.str());
739 OutStreamer->emitBytes(Data: VersionEBCDIC.str());
740
741 OutStreamer->emitInt16(Value: 0x0000); // Service level string length.
742
743 // The binder requires that the offset to the PPA2 be emitted in a different,
744 // specially-named section.
745 OutStreamer->switchSection(Section: getObjFileLowering().getPPA2ListSection());
746 // Emit 8 byte alignment.
747 // Emit pointer to PPA2 label.
748 OutStreamer->AddComment(T: "A(PPA2-CELQSTRT)");
749 OutStreamer->emitAbsoluteSymbolDiff(Hi: PPA2Sym, Lo: CELQSTRT, Size: 8);
750 OutStreamer->popSection();
751}
752
753void SystemZXPLINKAsmPrinter::emitGlobalAlias(const Module &M,
754 const GlobalAlias &GA) {
755 if (!TM.getTargetTriple().isOSzOS())
756 return AsmPrinter::emitGlobalAlias(M, GA);
757
758 // Aliased function labels have already been emitted for z/OS
759}
760
761const MCExpr *SystemZXPLINKAsmPrinter::lowerConstant(const Constant *CV,
762 const Constant *BaseCV,
763 uint64_t Offset) {
764 const GlobalAlias *GA = dyn_cast<GlobalAlias>(Val: CV);
765 const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val: CV);
766 const Function *FV = dyn_cast<Function>(Val: CV);
767 bool IsFunc = !GV && (FV || (GA && isa<Function>(Val: GA->getAliaseeObject())));
768
769 MCSymbol *Sym = NULL;
770
771 if (GA)
772 Sym = getSymbol(GV: GA);
773 else if (IsFunc)
774 Sym = getSymbol(GV: FV);
775 else if (GV)
776 Sym = getSymbol(GV);
777
778 if (IsFunc) {
779 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeFunction);
780 if (FV->hasExternalLinkage())
781 return MCSpecifierExpr::create(Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext),
782 S: SystemZ::S_VCon, Ctx&: OutContext);
783 // Trigger creation of function descriptor in ADA for internal
784 // functions.
785 unsigned Disp = ADATable.insert(Sym, SlotKind: SystemZII::MO_ADA_DIRECT_FUNC_DESC);
786 return MCBinaryExpr::createAdd(
787 LHS: MCSpecifierExpr::create(
788 Expr: MCSymbolRefExpr::create(
789 Symbol: getObjFileLowering().getADASection()->getBeginSymbol(),
790 Ctx&: OutContext),
791 S: SystemZ::S_None, Ctx&: OutContext),
792 RHS: MCConstantExpr::create(Value: Disp, Ctx&: OutContext), Ctx&: OutContext);
793 }
794 if (Sym) {
795 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeObject);
796 return MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext);
797 }
798 return AsmPrinter::lowerConstant(CV);
799}
800
801void SystemZXPLINKAsmPrinter::emitFunctionEntryLabel() {
802 auto *ZOS = getTargetStreamer();
803 calculatePPA1();
804
805 // EntryPoint Marker
806 const MachineFrameInfo &MFFrame = MF->getFrameInfo();
807 bool IsUsingAlloca = MFFrame.hasVarSizedObjects();
808 uint32_t DSASize = MFFrame.getStackSize();
809 bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty();
810
811 // Set Flags.
812 uint8_t Flags = 0;
813 if (IsLeaf)
814 Flags |= 0x08;
815 if (IsUsingAlloca)
816 Flags |= 0x04;
817
818 // Combine into top 27 bits of DSASize and bottom 5 bits of Flags.
819 uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 5
820 DSAAndFlags |= Flags;
821
822 // Emit entry point marker section.
823 OutStreamer->AddComment(T: "XPLINK Routine Layout Entry");
824 OutStreamer->emitLabel(Symbol: ZOS->DeferredPPA1.back().EPMarker);
825 OutStreamer->AddComment(T: "Eyecatcher 0x00C300C500C500");
826 OutStreamer->emitIntValueInHex(Value: 0x00C300C500C500, Size: 7); // Eyecatcher.
827 OutStreamer->AddComment(T: "Mark Type C'1'");
828 OutStreamer->emitInt8(Value: 0xF1); // Mark Type.
829 OutStreamer->AddComment(T: "Offset to PPA1");
830 OutStreamer->emitAbsoluteSymbolDiff(Hi: ZOS->DeferredPPA1.back().PPA1,
831 Lo: ZOS->DeferredPPA1.back().EPMarker, Size: 4);
832 if (OutStreamer->isVerboseAsm()) {
833 OutStreamer->AddComment(T: "DSA Size 0x" + Twine::utohexstr(Val: DSASize));
834 OutStreamer->AddComment(T: "Entry Flags");
835 if (Flags & 0x08)
836 OutStreamer->AddComment(T: " Bit 1: 1 = Leaf function");
837 else
838 OutStreamer->AddComment(T: " Bit 1: 0 = Non-leaf function");
839 if (Flags & 0x04)
840 OutStreamer->AddComment(T: " Bit 2: 1 = Uses alloca");
841 else
842 OutStreamer->AddComment(T: " Bit 2: 0 = Does not use alloca");
843 }
844 OutStreamer->emitInt32(Value: DSAAndFlags);
845
846 ZOS->emitADA(Sym: CurrentFnSym, Section: getObjFileLowering().getADASection());
847
848 AsmPrinter::emitFunctionEntryLabel();
849
850 const Function *F = &MF->getFunction();
851 // Emit aliasing label for function entry point label.
852 for (const GlobalAlias *Alias : GOAliasMap[F]) {
853 MCSymbol *Sym = getSymbol(GV: Alias);
854 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeFunction);
855 emitVisibility(Sym, Visibility: Alias->getVisibility());
856 emitLinkage(GV: Alias, GVSym: Sym);
857 OutStreamer->emitLabel(Symbol: Sym);
858 }
859}
860