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