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