1//===- SystemZHLASMAsmStreamer.cpp - HLASM Assembly Text Output -----------===//
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#include "SystemZHLASMAsmStreamer.h"
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/BinaryFormat/GOFF.h"
12#include "llvm/MC/MCExpr.h"
13#include "llvm/MC/MCSectionGOFF.h"
14#include "llvm/MC/MCSymbolGOFF.h"
15#include "llvm/Support/Casting.h"
16#include "llvm/Support/Format.h"
17#include "llvm/Support/Signals.h"
18#include <sstream>
19
20using namespace llvm;
21
22void SystemZHLASMAsmStreamer::visitUsedSymbol(const MCSymbol &Sym) {
23 Assembler->registerSymbol(Symbol: Sym);
24}
25
26void SystemZHLASMAsmStreamer::EmitEOL() {
27 // Comments are emitted on a new line before the instruction.
28 if (IsVerboseAsm)
29 EmitComment();
30
31 std::istringstream Stream(Str);
32 SmallVector<std::string> Lines;
33 std::string Line;
34 while (std::getline(in&: Stream, str&: Line, delim: '\n'))
35 Lines.push_back(Elt: Line);
36
37 for (auto S : Lines) {
38 if (LLVM_LIKELY(S.length() < ContIndicatorColumn)) {
39 FOS << S;
40 // Each line in HLASM must fill the full 80 characters.
41 FOS.PadToColumn(NewCol: InstLimit);
42 FOS << "\n";
43 } else {
44 // If last character before end of the line is not a space
45 // we must insert an additional non-space character that
46 // is not part of the statement coding. We just reuse
47 // the existing character by making the new substring start
48 // 1 character sooner, thus "duplicating" that character
49 // If The last character is a space. We insert an X instead.
50 std::string TmpSubStr = S.substr(pos: 0, n: ContIndicatorColumn);
51 if (!TmpSubStr.compare(pos: ContIndicatorColumn - 1, n1: 1, s: " "))
52 TmpSubStr.replace(pos: ContIndicatorColumn - 1, n1: 1, s: "X");
53
54 FOS << TmpSubStr;
55 FOS.PadToColumn(NewCol: InstLimit);
56 FOS << "\n";
57
58 size_t Emitted = ContIndicatorColumn - 1;
59
60 while (Emitted < S.length()) {
61 if ((S.length() - Emitted) < ContLen)
62 TmpSubStr = S.substr(pos: Emitted, n: S.length());
63 else {
64 TmpSubStr = S.substr(pos: Emitted, n: ContLen);
65 if (!TmpSubStr.compare(pos: ContLen - 1, n1: 1, s: " "))
66 TmpSubStr.replace(pos: ContLen - 1, n1: 1, s: "X");
67 }
68 FOS.PadToColumn(NewCol: ContStartColumn);
69 FOS << TmpSubStr;
70 FOS.PadToColumn(NewCol: InstLimit);
71 FOS << "\n";
72 Emitted += ContLen - 1;
73 }
74 }
75 }
76 Str.clear();
77}
78
79static void emitXATTR(raw_ostream &OS, StringRef Name, MCSectionGOFF *ADA,
80 bool IsIndirectReference, GOFF::ESDLinkageType Linkage,
81 GOFF::ESDExecutable Executable,
82 GOFF::ESDBindingScope BindingScope) {
83 llvm::ListSeparator Sep(",");
84 OS << Name << " XATTR ";
85 OS << Sep << "LINKAGE(" << (Linkage == GOFF::ESD_LT_OS ? "OS" : "XPLINK")
86 << ")";
87
88 const bool NotUnspecified = (Executable != GOFF::ESD_EXE_Unspecified);
89 if (NotUnspecified || IsIndirectReference) {
90 OS << Sep << "REFERENCE(";
91 llvm::ListSeparator SepRef(",");
92
93 if (NotUnspecified)
94 OS << SepRef << (Executable == GOFF::ESD_EXE_CODE ? "CODE" : "DATA");
95
96 if (IsIndirectReference)
97 OS << SepRef << "INDIRECT";
98
99 OS << ")";
100 }
101 // Emit PSECT only for code symbols.
102 if (ADA && Executable != GOFF::ESD_EXE_DATA)
103 OS << Sep << "PSECT(" << ADA->getName() << ")";
104 if (BindingScope != GOFF::ESD_BSC_Unspecified) {
105 OS << Sep << "SCOPE(";
106 switch (BindingScope) {
107 case GOFF::ESD_BSC_Section:
108 OS << "SECTION";
109 break;
110 case GOFF::ESD_BSC_Module:
111 OS << "MODULE";
112 break;
113 case GOFF::ESD_BSC_Library:
114 OS << "LIBRARY";
115 break;
116 case GOFF::ESD_BSC_ImportExport:
117 OS << "EXPORT";
118 break;
119 default:
120 break;
121 }
122 OS << ')';
123 }
124}
125
126static void emitCATTR(raw_ostream &OS, StringRef Name, GOFF::ESDRmode Rmode,
127 GOFF::ESDAlignment Alignment,
128 GOFF::ESDLoadingBehavior LoadBehavior,
129 GOFF::ESDExecutable Executable, bool IsReadOnly,
130 uint32_t SortKey, uint8_t FillByteValue,
131 StringRef PartName) {
132 OS << Name << " CATTR ";
133 OS << "ALIGN(" << static_cast<unsigned>(Alignment) << "),"
134 << "FILL(" << static_cast<unsigned>(FillByteValue) << ")";
135 switch (LoadBehavior) {
136 case GOFF::ESD_LB_Deferred:
137 OS << ",DEFLOAD";
138 break;
139 case GOFF::ESD_LB_NoLoad:
140 OS << ",NOLOAD";
141 break;
142 default:
143 break;
144 }
145 switch (Executable) {
146 case GOFF::ESD_EXE_CODE:
147 OS << ",EXECUTABLE";
148 break;
149 case GOFF::ESD_EXE_DATA:
150 OS << ",NOTEXECUTABLE";
151 break;
152 default:
153 break;
154 }
155 if (IsReadOnly)
156 OS << ",READONLY";
157 if (Rmode != GOFF::ESD_RMODE_None) {
158 OS << ',';
159 OS << "RMODE(";
160 switch (Rmode) {
161 case GOFF::ESD_RMODE_None:
162 llvm_unreachable("");
163 case GOFF::ESD_RMODE_24:
164 OS << "24";
165 break;
166 case GOFF::ESD_RMODE_31:
167 OS << "31";
168 break;
169 case GOFF::ESD_RMODE_64:
170 OS << "64";
171 break;
172 }
173 OS << ')';
174 }
175 if (SortKey)
176 OS << ",PRIORITY(" << SortKey << ")";
177 if (!PartName.empty())
178 OS << ",PART(" << PartName << ")";
179 OS << '\n';
180}
181
182static void emitALIAS(raw_ostream &OS, StringRef Name, StringRef ExternalName) {
183 OS << Name << " ALIAS C'";
184 for (char C : ExternalName) {
185 if (C == '\'' || C == '&')
186 OS << C;
187 OS << C;
188 }
189 OS << "'\n";
190}
191
192void SystemZHLASMAsmStreamer::changeSection(MCSection *Section,
193 uint32_t Subsection) {
194 auto &Sec = *static_cast<MCSectionGOFF *>(Section);
195 auto EmitExternalName = [&Sec, this]() {
196 if (Sec.hasExternalName())
197 emitALIAS(OS, Name: Sec.getName(), ExternalName: Sec.getExternalName());
198 };
199 switch (Sec.getSymbolType()) {
200 case GOFF::ESD_ST_SectionDefinition: {
201 OS << Sec.getName() << " CSECT\n";
202 Sec.setEmitted();
203 EmitExternalName();
204 break;
205 }
206 case GOFF::ESD_ST_ElementDefinition: {
207 changeSection(Section: Sec.getParent(), Subsection);
208 if (!Sec.isEmitted()) {
209 GOFF::EDAttr ED = Sec.getEDAttributes();
210 emitCATTR(OS, Name: Sec.getName(), Rmode: ED.Rmode, Alignment: Sec.getEDAlignment(),
211 LoadBehavior: ED.LoadBehavior, Executable: GOFF::ESD_EXE_Unspecified, IsReadOnly: ED.IsReadOnly, SortKey: 0,
212 FillByteValue: ED.FillByteValue, PartName: StringRef());
213 if (auto *BeginSym = static_cast<MCSymbolGOFF *>(Sec.getBeginSymbol())) {
214 if (BeginSym->getADA()) {
215 emitXATTR(OS, Name: BeginSym->getName(), ADA: BeginSym->getADA(),
216 /*IsIndirectReference=*/false, Linkage: GOFF::ESD_LT_XPLink,
217 Executable: GOFF::ESD_EXE_Unspecified, BindingScope: GOFF::ESD_BSC_Section);
218 OS << '\n';
219 }
220 }
221 Sec.setEmitted();
222 EmitExternalName();
223 } else
224 OS << Sec.getName() << " CATTR\n";
225 break;
226 }
227 case GOFF::ESD_ST_PartReference: {
228 MCSectionGOFF *ED = Sec.getParent();
229 changeSection(Section: ED->getParent(), Subsection);
230 if (!Sec.isEmitted()) {
231 GOFF::EDAttr EDAttr = ED->getEDAttributes();
232 GOFF::PRAttr PRAttr = Sec.getPRAttributes();
233 emitCATTR(OS, Name: ED->getName(), Rmode: EDAttr.Rmode, Alignment: ED->getEDAlignment(),
234 LoadBehavior: EDAttr.LoadBehavior, Executable: PRAttr.Executable, IsReadOnly: EDAttr.IsReadOnly,
235 SortKey: PRAttr.SortKey, FillByteValue: EDAttr.FillByteValue, PartName: Sec.getName());
236 MCSectionGOFF *ADA =
237 Sec.getBeginSymbol() != nullptr
238 ? static_cast<MCSymbolGOFF *>(Sec.getBeginSymbol())->getADA()
239 : nullptr;
240 emitXATTR(OS, Name: Sec.getName(), ADA, /*IsIndirectReference=*/false,
241 Linkage: PRAttr.Linkage, Executable: PRAttr.Executable, BindingScope: PRAttr.BindingScope);
242 OS << '\n';
243 ED->setEmitted();
244 Sec.setEmitted();
245 EmitExternalName();
246 } else
247 OS << ED->getName() << " CATTR PART(" << Sec.getName() << ")\n";
248 break;
249 }
250 default:
251 llvm_unreachable("Wrong section type");
252 }
253 MCStreamer::changeSection(Section, Subsection);
254 EmitEOL();
255}
256
257void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment,
258 std::optional<int64_t> Value,
259 unsigned ValueSize,
260 unsigned MaxBytesToEmit) {
261 if (!isPowerOf2_64(Value: ByteAlignment))
262 report_fatal_error(reason: "Only power-of-two alignments are supported ");
263
264 OS << " DS 0";
265 switch (ValueSize) {
266 default:
267 llvm_unreachable("Invalid size for machine code value!");
268 case 1:
269 OS << "B";
270 break;
271 case 2:
272 OS << "H";
273 break;
274 case 4:
275 OS << "F";
276 break;
277 case 8:
278 OS << "D";
279 break;
280 case 16:
281 OS << "Q";
282 break;
283 }
284
285 EmitEOL();
286}
287
288void SystemZHLASMAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {
289 OS << MAI->getCommentString() << T;
290 EmitEOL();
291}
292
293void SystemZHLASMAsmStreamer::AddComment(const Twine &T, bool EOL) {
294 if (!IsVerboseAsm)
295 return;
296
297 T.toVector(Out&: CommentToEmit);
298
299 if (EOL)
300 CommentToEmit.push_back(Elt: '\n'); // Place comment in a new line.
301}
302
303void SystemZHLASMAsmStreamer::EmitComment() {
304 if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0)
305 return;
306
307 StringRef Comments = CommentToEmit;
308
309 assert(Comments.back() == '\n' && "Comment array not newline terminated");
310 do {
311 // Emit a line of comments, but not exceeding 80 characters.
312 size_t Position = std::min(a: InstLimit - 2, b: Comments.find(C: '\n'));
313 FOS << MAI->getCommentString() << ' ' << Comments.substr(Start: 0, N: Position)
314 << '\n';
315
316 if (Comments[Position] == '\n')
317 Position++;
318 Comments = Comments.substr(Start: Position);
319 } while (!Comments.empty());
320
321 CommentToEmit.clear();
322}
323
324void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment,
325 int64_t Fill,
326 uint8_t FillLen,
327 unsigned MaxBytesToEmit) {
328 emitAlignmentDS(ByteAlignment: Alignment.value(), Value: Fill, ValueSize: FillLen, MaxBytesToEmit);
329}
330
331void SystemZHLASMAsmStreamer::emitCodeAlignment(Align Alignment,
332 const MCSubtargetInfo &STI,
333 unsigned MaxBytesToEmit) {
334 // Emit with a text fill value.
335 if (MAI->getTextAlignFillValue())
336 emitAlignmentDS(ByteAlignment: Alignment.value(), Value: MAI->getTextAlignFillValue(), ValueSize: 1,
337 MaxBytesToEmit);
338 else
339 emitAlignmentDS(ByteAlignment: Alignment.value(), Value: std::nullopt, ValueSize: 1, MaxBytesToEmit);
340}
341
342void SystemZHLASMAsmStreamer::emitBytes(StringRef Data) {
343 assert(getCurrentSectionOnly() &&
344 "Cannot emit contents before setting section!");
345 if (Data.empty())
346 return;
347
348 OS << " DC ";
349 size_t Len = Data.size();
350 SmallVector<uint8_t> Chars;
351 Chars.resize(N: Len);
352 OS << "XL" << Len;
353 uint32_t Index = 0;
354 for (uint8_t C : Data) {
355 Chars[Index] = C;
356 Index++;
357 }
358
359 OS << '\'' << toHex(Input: Chars) << '\'';
360
361 EmitEOL();
362}
363
364void SystemZHLASMAsmStreamer::emitFill(const MCExpr &NumBytes,
365 uint64_t FillValue, SMLoc Loc) {
366 int64_t Count;
367 if (!NumBytes.evaluateAsAbsolute(Res&: Count)) {
368 getContext().reportError(L: Loc, Msg: "fill length must be absolute in HLASM");
369 return;
370 }
371 if (Count < 0) {
372 getContext().reportError(L: Loc, Msg: "invalid number of bytes");
373 return;
374 }
375 if (Count > 0x7FFFFFFF) {
376 getContext().reportError(L: Loc, Msg: "fill length too large for HLASM");
377 return;
378 }
379 if (Count == 0)
380 return;
381
382 OS << " DC " << Count << "XL1'"
383 << format_hex_no_prefix(N: FillValue & 0xff, Width: 2, Upper: true) << '\'';
384 EmitEOL();
385}
386
387void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
388 const MCSubtargetInfo &STI) {
389 raw_ostream &OS = getCommentOS();
390 SmallString<256> Code;
391 SmallVector<MCFixup, 4> Fixups;
392
393 // If we have no code emitter, don't emit code.
394 if (!getAssembler().getEmitterPtr())
395 return;
396
397 getAssembler().getEmitter().encodeInstruction(Inst, CB&: Code, Fixups, STI);
398
399 // If we are showing fixups, create symbolic markers in the encoded
400 // representation. We do this by making a per-bit map to the fixup item index,
401 // then trying to display it as nicely as possible.
402 SmallVector<uint8_t, 64> FixupMap;
403 FixupMap.resize(N: Code.size() * 8);
404 for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
405 FixupMap[I] = 0;
406
407 for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
408 MCFixup &F = Fixups[I];
409 MCFixupKindInfo Info =
410 getAssembler().getBackend().getFixupKindInfo(Kind: F.getKind());
411 for (unsigned J = 0; J != Info.TargetSize; ++J) {
412 unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
413 assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
414 FixupMap[Index] = 1 + I;
415 }
416 }
417
418 OS << "encoding: [";
419 for (unsigned I = 0, E = Code.size(); I != E; ++I) {
420 if (I)
421 OS << ',';
422
423 // See if all bits are the same map entry.
424 uint8_t MapEntry = FixupMap[I * 8 + 0];
425 for (unsigned J = 1; J != 8; ++J) {
426 if (FixupMap[I * 8 + J] == MapEntry)
427 continue;
428
429 MapEntry = uint8_t(~0U);
430 break;
431 }
432
433 if (MapEntry != uint8_t(~0U)) {
434 if (MapEntry == 0) {
435 OS << format(Fmt: "0x%02x", Vals: uint8_t(Code[I]));
436 } else {
437 if (Code[I]) {
438 // FIXME: Some of the 8 bits require fix up.
439 OS << format(Fmt: "0x%02x", Vals: uint8_t(Code[I])) << '\''
440 << char('A' + MapEntry - 1) << '\'';
441 } else
442 OS << char('A' + MapEntry - 1);
443 }
444 } else {
445 // Otherwise, write out in binary.
446 OS << "0b";
447 for (unsigned J = 8; J--;) {
448 unsigned Bit = (Code[I] >> J) & 1;
449 unsigned FixupBit = I * 8 + (7 - J);
450 if (uint8_t MapEntry = FixupMap[FixupBit]) {
451 assert(Bit == 0 && "Encoder wrote into fixed up bit!");
452 OS << char('A' + MapEntry - 1);
453 } else
454 OS << Bit;
455 }
456 }
457 }
458 OS << "]\n";
459
460 for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
461 MCFixup &F = Fixups[I];
462 OS << " fixup " << char('A' + I) << " - "
463 << "offset: " << F.getOffset() << ", value: ";
464 MAI->printExpr(OS, *F.getValue());
465 auto Kind = F.getKind();
466 if (mc::isRelocation(FixupKind: Kind))
467 OS << ", relocation type: " << Kind;
468 else {
469 OS << ", kind: ";
470 auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
471 if (F.isPCRel() && StringRef(Info.Name).starts_with(Prefix: "FK_Data_"))
472 OS << "FK_PCRel_" << (Info.TargetSize / 8);
473 else
474 OS << Info.Name;
475 }
476 OS << "\n";
477 }
478}
479
480void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
481 const MCSubtargetInfo &STI) {
482 // Show the encoding in a comment if we have a code emitter.
483 addEncodingComment(Inst, STI);
484 EmitEOL();
485
486 InstPrinter->printInst(MI: &Inst, Address: 0, Annot: "", STI, OS);
487 EmitEOL();
488}
489
490void SystemZHLASMAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
491 MCSymbolGOFF *Sym = static_cast<MCSymbolGOFF *>(Symbol);
492
493 MCStreamer::emitLabel(Symbol: Sym, Loc);
494
495 // Emit label and ENTRY statement only if not implied by CSECT. Do not emit a
496 // label if the symbol is on a PR section.
497 bool EmitLabelAndEntry =
498 !static_cast<MCSectionGOFF *>(getCurrentSectionOnly())->isPR();
499 if (!Sym->isTemporary() && Sym->isInEDSection()) {
500 EmitLabelAndEntry =
501 Sym->getName() !=
502 static_cast<MCSectionGOFF &>(Sym->getSection()).getParent()->getName();
503 if (EmitLabelAndEntry) {
504 OS << " ENTRY " << Sym->getName();
505 EmitEOL();
506 }
507
508 emitXATTR(OS, Name: Sym->getName(), ADA: Sym->getADA(), IsIndirectReference: Sym->isIndirect(),
509 Linkage: Sym->getLinkage(), Executable: Sym->getCodeData(), BindingScope: Sym->getBindingScope());
510 EmitEOL();
511 if (Sym->hasExternalName())
512 emitALIAS(OS, Name: Sym->getName(), ExternalName: Sym->getExternalName());
513 }
514
515 if (EmitLabelAndEntry) {
516 OS << Sym->getName() << " DS 0H";
517 EmitEOL();
518 }
519}
520
521bool SystemZHLASMAsmStreamer::emitSymbolAttribute(MCSymbol *Sym,
522 MCSymbolAttr Attribute) {
523 return static_cast<MCSymbolGOFF *>(Sym)->setSymbolAttribute(Attribute);
524}
525
526void SystemZHLASMAsmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
527 Align ByteAlignment) {
528 auto *Symbol = static_cast<MCSymbolGOFF *>(S);
529 MCSectionGOFF *Section =
530 Symbol->getSectionForCommonSymbol(Ctx&: getContext(), ByteAlignment);
531 pushSection();
532 switchSection(Section);
533 emitLabel(Symbol, Loc: SMLoc());
534 emitZeros(NumBytes: Size);
535 popSection();
536}
537
538void SystemZHLASMAsmStreamer::emitRawTextImpl(StringRef String) {
539 String.consume_back(Suffix: "\n");
540 OS << String;
541 EmitEOL();
542}
543
544// Slight duplicate of MCExpr::print due to HLASM only recognizing limited
545// arithmetic operators (+-*/).
546void SystemZHLASMAsmStreamer::emitHLASMValueImpl(const MCExpr *Value,
547 unsigned Size, bool Parens) {
548 switch (Value->getKind()) {
549 case MCExpr::Constant: {
550 int64_t Val = cast<MCConstantExpr>(Val: Value)->getValue();
551 OS << "XL" << Size << '\''
552 << format_hex_no_prefix(N: Val, Width: Size * 2, /*Upper=*/true) << '\'';
553 return;
554 }
555 case MCExpr::Binary: {
556 const MCBinaryExpr &BE = cast<MCBinaryExpr>(Val: *Value);
557 int64_t Const;
558 // Or is handled differently.
559 if (BE.getOpcode() == MCBinaryExpr::Or) {
560 emitHLASMValueImpl(Value: BE.getLHS(), Size, Parens: true);
561 OS << ',';
562 emitHLASMValueImpl(Value: BE.getRHS(), Size, Parens: true);
563 return;
564 }
565
566 if (Parens)
567 OS << "AD(";
568 emitHLASMValueImpl(Value: BE.getLHS(), Size);
569
570 switch (BE.getOpcode()) {
571 case MCBinaryExpr::LShr: {
572 Const = cast<MCConstantExpr>(Val: BE.getRHS())->getValue();
573 OS << '/' << (1 << Const);
574 if (Parens)
575 OS << ')';
576 return;
577 }
578 case MCBinaryExpr::Add:
579 OS << '+';
580 break;
581 case MCBinaryExpr::Div:
582 OS << '/';
583 break;
584 case MCBinaryExpr::Mul:
585 OS << '*';
586 break;
587 case MCBinaryExpr::Sub:
588 OS << '-';
589 break;
590 default:
591 getContext().reportError(L: SMLoc(),
592 Msg: "Unrecognized HLASM arithmetic expression!");
593 }
594 emitHLASMValueImpl(Value: BE.getRHS(), Size);
595 if (Parens)
596 OS << ')';
597 return;
598 }
599 case MCExpr::Target:
600 MAI->printExpr(OS, *Value);
601 return;
602 default:
603 Parens &= isa<MCSymbolRefExpr>(Val: Value);
604 if (Parens)
605 OS << "AD(";
606 MAI->printExpr(OS, *Value);
607 if (Parens)
608 OS << ')';
609 return;
610 }
611}
612
613void SystemZHLASMAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
614 SMLoc Loc) {
615 assert(Size <= 8 && "Invalid size");
616 assert(getCurrentSectionOnly() &&
617 "Cannot emit contents before setting section!");
618
619 MCStreamer::emitValueImpl(Value, Size, Loc);
620 OS << " DC ";
621 emitHLASMValueImpl(Value, Size, Parens: true);
622 EmitEOL();
623}
624
625void SystemZHLASMAsmStreamer::finishImpl() {
626 for (auto &Symbol : getAssembler().symbols()) {
627 if (Symbol.isTemporary() || !Symbol.isRegistered() || Symbol.isDefined())
628 continue;
629 auto &Sym = static_cast<MCSymbolGOFF &>(const_cast<MCSymbol &>(Symbol));
630 if (Sym.getCodeData() == GOFF::ESD_EXE_DATA) {
631 OS << Sym.getADA()->getParent()->getExternalName() << " CATTR PART("
632 << Sym.getName() << ")";
633 EmitEOL();
634 } else {
635 OS << " " << (Sym.isWeak() ? "WXTRN" : "EXTRN") << " " << Sym.getName();
636 EmitEOL();
637 }
638 emitXATTR(OS, Name: Sym.getName(), ADA: Sym.getADA(), IsIndirectReference: Sym.isIndirect(),
639 Linkage: Sym.getLinkage(), Executable: Sym.getCodeData(), BindingScope: Sym.getBindingScope());
640 EmitEOL();
641 if (Sym.hasExternalName())
642 emitALIAS(OS, Name: Sym.getName(), ExternalName: Sym.getExternalName());
643 }
644
645 // Finish the assembly output.
646 OS << " END";
647 EmitEOL();
648}
649