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