| 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 | |
| 35 | using namespace llvm; |
| 36 | |
| 37 | SystemZXPLINKAsmPrinter::SystemZXPLINKAsmPrinter( |
| 38 | TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) |
| 39 | : SystemZAsmPrinter(TM, std::move(Streamer)), ADATable(8) {} |
| 40 | |
| 41 | bool 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. |
| 74 | void 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 | |
| 81 | uint32_t |
| 82 | SystemZXPLINKAsmPrinter::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 | |
| 108 | uint32_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 | |
| 126 | void 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 | |
| 211 | void 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 | |
| 272 | void 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. |
| 301 | void 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 | |
| 338 | void 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 (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 | |
| 411 | static 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 | |
| 420 | static 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 | |
| 427 | static 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 | |
| 434 | static 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 | |
| 441 | static 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 | |
| 451 | void 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 | |
| 477 | void 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. |
| 486 | static 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 | |
| 561 | void 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 | |
| 682 | void 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 | |
| 694 | void 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 | |
| 808 | void 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 | |
| 816 | const 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 | |
| 868 | void 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 | |