1//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===//
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 "llvm/ADT/SmallString.h"
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/ADT/Twine.h"
12#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
13#include "llvm/MC/MCAsmBackend.h"
14#include "llvm/MC/MCAsmInfo.h"
15#include "llvm/MC/MCAssembler.h"
16#include "llvm/MC/MCCodeEmitter.h"
17#include "llvm/MC/MCCodeView.h"
18#include "llvm/MC/MCContext.h"
19#include "llvm/MC/MCExpr.h"
20#include "llvm/MC/MCFixupKindInfo.h"
21#include "llvm/MC/MCInst.h"
22#include "llvm/MC/MCInstPrinter.h"
23#include "llvm/MC/MCObjectFileInfo.h"
24#include "llvm/MC/MCObjectWriter.h"
25#include "llvm/MC/MCPseudoProbe.h"
26#include "llvm/MC/MCRegister.h"
27#include "llvm/MC/MCRegisterInfo.h"
28#include "llvm/MC/MCSectionMachO.h"
29#include "llvm/MC/MCStreamer.h"
30#include "llvm/MC/MCSymbolXCOFF.h"
31#include "llvm/MC/TargetRegistry.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/Format.h"
35#include "llvm/Support/FormattedStream.h"
36#include "llvm/Support/LEB128.h"
37#include "llvm/Support/MathExtras.h"
38#include "llvm/Support/Path.h"
39#include <algorithm>
40#include <optional>
41
42using namespace llvm;
43
44namespace {
45
46class MCAsmStreamer final : public MCStreamer {
47 std::unique_ptr<formatted_raw_ostream> OSOwner;
48 formatted_raw_ostream &OS;
49 const MCAsmInfo *MAI;
50 std::unique_ptr<MCInstPrinter> InstPrinter;
51 std::unique_ptr<MCAssembler> Assembler;
52
53 SmallString<128> ExplicitCommentToEmit;
54 SmallString<128> CommentToEmit;
55 raw_svector_ostream CommentStream;
56 raw_null_ostream NullStream;
57
58 bool IsVerboseAsm = false;
59 bool ShowInst = false;
60 bool UseDwarfDirectory = false;
61
62 void EmitRegisterName(int64_t Register);
63 void PrintQuotedString(StringRef Data, raw_ostream &OS) const;
64 void printDwarfFileDirective(unsigned FileNo, StringRef Directory,
65 StringRef Filename,
66 std::optional<MD5::MD5Result> Checksum,
67 std::optional<StringRef> Source,
68 bool UseDwarfDirectory,
69 raw_svector_ostream &OS) const;
70 void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
71 void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
72
73public:
74 MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> os,
75 MCInstPrinter *printer, std::unique_ptr<MCCodeEmitter> emitter,
76 std::unique_ptr<MCAsmBackend> asmbackend)
77 : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner),
78 MAI(Context.getAsmInfo()), InstPrinter(printer),
79 Assembler(std::make_unique<MCAssembler>(
80 args&: Context, args: std::move(asmbackend), args: std::move(emitter),
81 args: (asmbackend) ? asmbackend->createObjectWriter(OS&: NullStream)
82 : nullptr)),
83 CommentStream(CommentToEmit) {
84 assert(InstPrinter);
85 if (Assembler->getBackendPtr())
86 setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
87
88 Context.setUseNamesOnTempLabels(true);
89
90 auto *TO = Context.getTargetOptions();
91 if (!TO)
92 return;
93 IsVerboseAsm = TO->AsmVerbose;
94 if (IsVerboseAsm)
95 InstPrinter->setCommentStream(CommentStream);
96 ShowInst = TO->ShowMCInst;
97 switch (TO->MCUseDwarfDirectory) {
98 case MCTargetOptions::DisableDwarfDirectory:
99 UseDwarfDirectory = false;
100 break;
101 case MCTargetOptions::EnableDwarfDirectory:
102 UseDwarfDirectory = true;
103 break;
104 case MCTargetOptions::DefaultDwarfDirectory:
105 UseDwarfDirectory =
106 Context.getAsmInfo()->enableDwarfFileDirectoryDefault();
107 break;
108 }
109 }
110
111 MCAssembler &getAssembler() { return *Assembler; }
112 MCAssembler *getAssemblerPtr() override { return nullptr; }
113
114 inline void EmitEOL() {
115 // Dump Explicit Comments here.
116 emitExplicitComments();
117 // If we don't have any comments, just emit a \n.
118 if (!IsVerboseAsm) {
119 OS << '\n';
120 return;
121 }
122 EmitCommentsAndEOL();
123 }
124
125 void emitSyntaxDirective() override;
126
127 void EmitCommentsAndEOL();
128
129 /// Return true if this streamer supports verbose assembly at all.
130 bool isVerboseAsm() const override { return IsVerboseAsm; }
131
132 /// Do we support EmitRawText?
133 bool hasRawTextSupport() const override { return true; }
134
135 /// Add a comment that can be emitted to the generated .s file to make the
136 /// output of the compiler more readable. This only affects the MCAsmStreamer
137 /// and only when verbose assembly output is enabled.
138 void AddComment(const Twine &T, bool EOL = true) override;
139
140 /// Add a comment showing the encoding of an instruction.
141 void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &);
142
143 /// Return a raw_ostream that comments can be written to.
144 /// Unlike AddComment, you are required to terminate comments with \n if you
145 /// use this method.
146 raw_ostream &getCommentOS() override {
147 if (!IsVerboseAsm)
148 return nulls(); // Discard comments unless in verbose asm mode.
149 return CommentStream;
150 }
151
152 void emitRawComment(const Twine &T, bool TabPrefix = true) override;
153
154 void addExplicitComment(const Twine &T) override;
155 void emitExplicitComments() override;
156
157 /// Emit a blank line to a .s file to pretty it up.
158 void addBlankLine() override { EmitEOL(); }
159
160 /// @name MCStreamer Interface
161 /// @{
162
163 void changeSection(MCSection *Section, uint32_t Subsection) override;
164
165 void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
166 bool KeepOriginalSym) override;
167
168 void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;
169
170 void emitGNUAttribute(unsigned Tag, unsigned Value) override;
171
172 StringRef getMnemonic(MCInst &MI) override {
173 auto [Ptr, Bits] = InstPrinter->getMnemonic(MI: &MI);
174 assert((Bits != 0 || Ptr == nullptr) &&
175 "Invalid char pointer for instruction with no mnemonic");
176 return Ptr;
177 }
178
179 void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
180
181 void emitAssemblerFlag(MCAssemblerFlag Flag) override;
182 void emitLinkerOptions(ArrayRef<std::string> Options) override;
183 void emitDataRegion(MCDataRegionType Kind) override;
184 void emitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
185 unsigned Update, VersionTuple SDKVersion) override;
186 void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
187 unsigned Update, VersionTuple SDKVersion) override;
188 void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major,
189 unsigned Minor, unsigned Update,
190 VersionTuple SDKVersion) override;
191 void emitThumbFunc(MCSymbol *Func) override;
192
193 void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
194 void emitConditionalAssignment(MCSymbol *Symbol,
195 const MCExpr *Value) override;
196 void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
197 bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
198
199 void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
200 void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
201 void emitCOFFSymbolStorageClass(int StorageClass) override;
202 void emitCOFFSymbolType(int Type) override;
203 void endCOFFSymbolDef() override;
204 void emitCOFFSafeSEH(MCSymbol const *Symbol) override;
205 void emitCOFFSymbolIndex(MCSymbol const *Symbol) override;
206 void emitCOFFSectionIndex(MCSymbol const *Symbol) override;
207 void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
208 void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
209 void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,
210 MCSymbol *CsectSym, Align Alignment) override;
211 void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
212 MCSymbolAttr Linkage,
213 MCSymbolAttr Visibility) override;
214 void emitXCOFFRenameDirective(const MCSymbol *Name,
215 StringRef Rename) override;
216
217 void emitXCOFFRefDirective(const MCSymbol *Symbol) override;
218
219 void emitXCOFFExceptDirective(const MCSymbol *Symbol,
220 const MCSymbol *Trap,
221 unsigned Lang, unsigned Reason,
222 unsigned FunctionSize, bool hasDebug) override;
223 void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;
224
225 void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
226 void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
227 Align ByteAlignment) override;
228
229 /// Emit a local common (.lcomm) symbol.
230 ///
231 /// @param Symbol - The common symbol to emit.
232 /// @param Size - The size of the common symbol.
233 /// @param ByteAlignment - The alignment of the common symbol in bytes.
234 void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
235 Align ByteAlignment) override;
236
237 void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
238 uint64_t Size = 0, Align ByteAlignment = Align(1),
239 SMLoc Loc = SMLoc()) override;
240
241 void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
242 Align ByteAlignment = Align(1)) override;
243
244 void emitBinaryData(StringRef Data) override;
245
246 void emitBytes(StringRef Data) override;
247
248 void emitValueImpl(const MCExpr *Value, unsigned Size,
249 SMLoc Loc = SMLoc()) override;
250 void emitIntValue(uint64_t Value, unsigned Size) override;
251 void emitIntValueInHex(uint64_t Value, unsigned Size) override;
252 void emitIntValueInHexWithPadding(uint64_t Value, unsigned Size) override;
253
254 void emitULEB128Value(const MCExpr *Value) override;
255
256 void emitSLEB128Value(const MCExpr *Value) override;
257
258 void emitDTPRel32Value(const MCExpr *Value) override;
259 void emitDTPRel64Value(const MCExpr *Value) override;
260 void emitTPRel32Value(const MCExpr *Value) override;
261 void emitTPRel64Value(const MCExpr *Value) override;
262
263 void emitGPRel64Value(const MCExpr *Value) override;
264
265 void emitGPRel32Value(const MCExpr *Value) override;
266
267 void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
268 SMLoc Loc = SMLoc()) override;
269
270 void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
271 SMLoc Loc = SMLoc()) override;
272
273 void emitAlignmentDirective(uint64_t ByteAlignment,
274 std::optional<int64_t> Value, unsigned ValueSize,
275 unsigned MaxBytesToEmit);
276
277 void emitValueToAlignment(Align Alignment, int64_t Value = 0,
278 unsigned ValueSize = 1,
279 unsigned MaxBytesToEmit = 0) override;
280
281 void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
282 unsigned MaxBytesToEmit = 0) override;
283
284 void emitValueToOffset(const MCExpr *Offset,
285 unsigned char Value,
286 SMLoc Loc) override;
287
288 void emitFileDirective(StringRef Filename) override;
289 void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
290 StringRef TimeStamp, StringRef Description) override;
291 Expected<unsigned> tryEmitDwarfFileDirective(
292 unsigned FileNo, StringRef Directory, StringRef Filename,
293 std::optional<MD5::MD5Result> Checksum = std::nullopt,
294 std::optional<StringRef> Source = std::nullopt,
295 unsigned CUID = 0) override;
296 void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,
297 std::optional<MD5::MD5Result> Checksum,
298 std::optional<StringRef> Source,
299 unsigned CUID = 0) override;
300 void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,
301 unsigned Flags, unsigned Isa,
302 unsigned Discriminator,
303 StringRef FileName) override;
304 MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
305
306 bool emitCVFileDirective(unsigned FileNo, StringRef Filename,
307 ArrayRef<uint8_t> Checksum,
308 unsigned ChecksumKind) override;
309 bool emitCVFuncIdDirective(unsigned FuncId) override;
310 bool emitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
311 unsigned IAFile, unsigned IALine,
312 unsigned IACol, SMLoc Loc) override;
313 void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
314 unsigned Column, bool PrologueEnd, bool IsStmt,
315 StringRef FileName, SMLoc Loc) override;
316 void emitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
317 const MCSymbol *FnEnd) override;
318 void emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
319 unsigned SourceFileId,
320 unsigned SourceLineNum,
321 const MCSymbol *FnStartSym,
322 const MCSymbol *FnEndSym) override;
323
324 void PrintCVDefRangePrefix(
325 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges);
326
327 void emitCVDefRangeDirective(
328 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
329 codeview::DefRangeRegisterRelHeader DRHdr) override;
330
331 void emitCVDefRangeDirective(
332 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
333 codeview::DefRangeSubfieldRegisterHeader DRHdr) override;
334
335 void emitCVDefRangeDirective(
336 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
337 codeview::DefRangeRegisterHeader DRHdr) override;
338
339 void emitCVDefRangeDirective(
340 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
341 codeview::DefRangeFramePointerRelHeader DRHdr) override;
342
343 void emitCVStringTableDirective() override;
344 void emitCVFileChecksumsDirective() override;
345 void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
346 void emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
347
348 void emitIdent(StringRef IdentString) override;
349 void emitCFIBKeyFrame() override;
350 void emitCFIMTETaggedFrame() override;
351 void emitCFISections(bool EH, bool Debug) override;
352 void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) override;
353 void emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) override;
354 void emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) override;
355 void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
356 int64_t AddressSpace, SMLoc Loc) override;
357 void emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
358 void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
359 void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
360 void emitCFIRememberState(SMLoc Loc) override;
361 void emitCFIRestoreState(SMLoc Loc) override;
362 void emitCFIRestore(int64_t Register, SMLoc Loc) override;
363 void emitCFISameValue(int64_t Register, SMLoc Loc) override;
364 void emitCFIRelOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
365 void emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) override;
366 void emitCFIEscape(StringRef Values, SMLoc Loc) override;
367 void emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) override;
368 void emitCFISignalFrame() override;
369 void emitCFIUndefined(int64_t Register, SMLoc Loc) override;
370 void emitCFIRegister(int64_t Register1, int64_t Register2,
371 SMLoc Loc) override;
372 void emitCFIWindowSave(SMLoc Loc) override;
373 void emitCFINegateRAState(SMLoc Loc) override;
374 void emitCFIReturnColumn(int64_t Register) override;
375 void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
376
377 void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
378 void emitWinCFIEndProc(SMLoc Loc) override;
379 void emitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
380 void emitWinCFIStartChained(SMLoc Loc) override;
381 void emitWinCFIEndChained(SMLoc Loc) override;
382 void emitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;
383 void emitWinCFISetFrame(MCRegister Register, unsigned Offset,
384 SMLoc Loc) override;
385 void emitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;
386 void emitWinCFISaveReg(MCRegister Register, unsigned Offset,
387 SMLoc Loc) override;
388 void emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
389 SMLoc Loc) override;
390 void emitWinCFIPushFrame(bool Code, SMLoc Loc) override;
391 void emitWinCFIEndProlog(SMLoc Loc) override;
392
393 void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
394 SMLoc Loc) override;
395 void emitWinEHHandlerData(SMLoc Loc) override;
396
397 void emitCGProfileEntry(const MCSymbolRefExpr *From,
398 const MCSymbolRefExpr *To, uint64_t Count) override;
399
400 void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
401
402 void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type,
403 uint64_t Attr, uint64_t Discriminator,
404 const MCPseudoProbeInlineStack &InlineStack,
405 MCSymbol *FnSym) override;
406
407 void emitBundleAlignMode(Align Alignment) override;
408 void emitBundleLock(bool AlignToEnd) override;
409 void emitBundleUnlock() override;
410
411 std::optional<std::pair<bool, std::string>>
412 emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr,
413 SMLoc Loc, const MCSubtargetInfo &STI) override;
414
415 void emitAddrsig() override;
416 void emitAddrsigSym(const MCSymbol *Sym) override;
417
418 /// If this file is backed by an assembly streamer, this dumps the specified
419 /// string in the output .s file. This capability is indicated by the
420 /// hasRawTextSupport() predicate.
421 void emitRawTextImpl(StringRef String) override;
422
423 void finishImpl() override;
424
425 void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) override;
426
427 MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
428 const Twine &Comment) override;
429
430 void emitDwarfLineStartLabel(MCSymbol *StartSym) override;
431
432 void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override;
433
434 void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
435 const MCSymbol *Label,
436 unsigned PointerSize) override;
437
438 void doFinalizationAtSectionEnd(MCSection *Section) override;
439};
440
441} // end anonymous namespace.
442
443void MCAsmStreamer::AddComment(const Twine &T, bool EOL) {
444 if (!IsVerboseAsm) return;
445
446 T.toVector(Out&: CommentToEmit);
447
448 if (EOL)
449 CommentToEmit.push_back(Elt: '\n'); // Place comment in a new line.
450}
451
452void MCAsmStreamer::EmitCommentsAndEOL() {
453 if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
454 OS << '\n';
455 return;
456 }
457
458 StringRef Comments = CommentToEmit;
459
460 assert(Comments.back() == '\n' &&
461 "Comment array not newline terminated");
462 do {
463 // Emit a line of comments.
464 OS.PadToColumn(NewCol: MAI->getCommentColumn());
465 size_t Position = Comments.find(C: '\n');
466 OS << MAI->getCommentString() << ' ' << Comments.substr(Start: 0, N: Position) <<'\n';
467
468 Comments = Comments.substr(Start: Position+1);
469 } while (!Comments.empty());
470
471 CommentToEmit.clear();
472}
473
474static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
475 assert(Bytes > 0 && Bytes <= 8 && "Invalid size!");
476 return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
477}
478
479void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {
480 if (TabPrefix)
481 OS << '\t';
482 OS << MAI->getCommentString() << T;
483 EmitEOL();
484}
485
486void MCAsmStreamer::addExplicitComment(const Twine &T) {
487 StringRef c = T.getSingleStringRef();
488 if (c == MAI->getSeparatorString())
489 return;
490 if (c.starts_with(Prefix: StringRef("//"))) {
491 ExplicitCommentToEmit.append(RHS: "\t");
492 ExplicitCommentToEmit.append(RHS: MAI->getCommentString());
493 // drop //
494 ExplicitCommentToEmit.append(RHS: c.slice(Start: 2, End: c.size()).str());
495 } else if (c.starts_with(Prefix: StringRef("/*"))) {
496 size_t p = 2, len = c.size() - 2;
497 // emit each line in comment as separate newline.
498 do {
499 size_t newp = std::min(a: len, b: c.find_first_of(Chars: "\r\n", From: p));
500 ExplicitCommentToEmit.append(RHS: "\t");
501 ExplicitCommentToEmit.append(RHS: MAI->getCommentString());
502 ExplicitCommentToEmit.append(RHS: c.slice(Start: p, End: newp).str());
503 // If we have another line in this comment add line
504 if (newp < len)
505 ExplicitCommentToEmit.append(RHS: "\n");
506 p = newp + 1;
507 } while (p < len);
508 } else if (c.starts_with(Prefix: StringRef(MAI->getCommentString()))) {
509 ExplicitCommentToEmit.append(RHS: "\t");
510 ExplicitCommentToEmit.append(RHS: c.str());
511 } else if (c.front() == '#') {
512
513 ExplicitCommentToEmit.append(RHS: "\t");
514 ExplicitCommentToEmit.append(RHS: MAI->getCommentString());
515 ExplicitCommentToEmit.append(RHS: c.slice(Start: 1, End: c.size()).str());
516 } else
517 assert(false && "Unexpected Assembly Comment");
518 // full line comments immediately output
519 if (c.back() == '\n')
520 emitExplicitComments();
521}
522
523void MCAsmStreamer::emitExplicitComments() {
524 StringRef Comments = ExplicitCommentToEmit;
525 if (!Comments.empty())
526 OS << Comments;
527 ExplicitCommentToEmit.clear();
528}
529
530void MCAsmStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
531 if (MCTargetStreamer *TS = getTargetStreamer()) {
532 TS->changeSection(CurSection: getCurrentSection().first, Section, SubSection: Subsection, OS);
533 } else {
534 Section->printSwitchToSection(MAI: *MAI, T: getContext().getTargetTriple(), OS,
535 Subsection);
536 }
537 MCStreamer::changeSection(Section, Subsection);
538}
539
540void MCAsmStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
541 StringRef Name,
542 bool KeepOriginalSym) {
543 OS << ".symver ";
544 OriginalSym->print(OS, MAI);
545 OS << ", " << Name;
546 if (!KeepOriginalSym && !Name.contains(Other: "@@@"))
547 OS << ", remove";
548 EmitEOL();
549}
550
551void MCAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
552 MCStreamer::emitLabel(Symbol, Loc);
553
554 Symbol->print(OS, MAI);
555 OS << MAI->getLabelSuffix();
556
557 EmitEOL();
558}
559
560void MCAsmStreamer::emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
561 StringRef str = MCLOHIdToName(Kind);
562
563#ifndef NDEBUG
564 int NbArgs = MCLOHIdToNbArgs(Kind);
565 assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");
566 assert(str != "" && "Invalid LOH name");
567#endif
568
569 OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";
570 bool IsFirst = true;
571 for (const MCSymbol *Arg : Args) {
572 if (!IsFirst)
573 OS << ", ";
574 IsFirst = false;
575 Arg->print(OS, MAI);
576 }
577 EmitEOL();
578}
579
580void MCAsmStreamer::emitGNUAttribute(unsigned Tag, unsigned Value) {
581 OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n";
582}
583
584void MCAsmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) {
585 switch (Flag) {
586 case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break;
587 case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break;
588 case MCAF_Code16: OS << '\t'<< MAI->getCode16Directive();break;
589 case MCAF_Code32: OS << '\t'<< MAI->getCode32Directive();break;
590 case MCAF_Code64: OS << '\t'<< MAI->getCode64Directive();break;
591 }
592 EmitEOL();
593}
594
595void MCAsmStreamer::emitLinkerOptions(ArrayRef<std::string> Options) {
596 assert(!Options.empty() && "At least one option is required!");
597 OS << "\t.linker_option \"" << Options[0] << '"';
598 for (const std::string &Opt : llvm::drop_begin(RangeOrContainer&: Options))
599 OS << ", " << '"' << Opt << '"';
600 EmitEOL();
601}
602
603void MCAsmStreamer::emitDataRegion(MCDataRegionType Kind) {
604 if (!MAI->doesSupportDataRegionDirectives())
605 return;
606 switch (Kind) {
607 case MCDR_DataRegion: OS << "\t.data_region"; break;
608 case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break;
609 case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break;
610 case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break;
611 case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break;
612 }
613 EmitEOL();
614}
615
616static const char *getVersionMinDirective(MCVersionMinType Type) {
617 switch (Type) {
618 case MCVM_WatchOSVersionMin: return ".watchos_version_min";
619 case MCVM_TvOSVersionMin: return ".tvos_version_min";
620 case MCVM_IOSVersionMin: return ".ios_version_min";
621 case MCVM_OSXVersionMin: return ".macosx_version_min";
622 }
623 llvm_unreachable("Invalid MC version min type");
624}
625
626static void EmitSDKVersionSuffix(raw_ostream &OS,
627 const VersionTuple &SDKVersion) {
628 if (SDKVersion.empty())
629 return;
630 OS << '\t' << "sdk_version " << SDKVersion.getMajor();
631 if (auto Minor = SDKVersion.getMinor()) {
632 OS << ", " << *Minor;
633 if (auto Subminor = SDKVersion.getSubminor()) {
634 OS << ", " << *Subminor;
635 }
636 }
637}
638
639void MCAsmStreamer::emitVersionMin(MCVersionMinType Type, unsigned Major,
640 unsigned Minor, unsigned Update,
641 VersionTuple SDKVersion) {
642 OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor;
643 if (Update)
644 OS << ", " << Update;
645 EmitSDKVersionSuffix(OS, SDKVersion);
646 EmitEOL();
647}
648
649static const char *getPlatformName(MachO::PlatformType Type) {
650 switch (Type) {
651#define PLATFORM(platform, id, name, build_name, target, tapi_target, \
652 marketing) \
653 case MachO::PLATFORM_##platform: \
654 return #build_name;
655#include "llvm/BinaryFormat/MachO.def"
656 }
657 llvm_unreachable("Invalid Mach-O platform type");
658}
659
660void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major,
661 unsigned Minor, unsigned Update,
662 VersionTuple SDKVersion) {
663 const char *PlatformName = getPlatformName(Type: (MachO::PlatformType)Platform);
664 OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor;
665 if (Update)
666 OS << ", " << Update;
667 EmitSDKVersionSuffix(OS, SDKVersion);
668 EmitEOL();
669}
670
671void MCAsmStreamer::emitDarwinTargetVariantBuildVersion(
672 unsigned Platform, unsigned Major, unsigned Minor, unsigned Update,
673 VersionTuple SDKVersion) {
674 emitBuildVersion(Platform, Major, Minor, Update, SDKVersion);
675}
676
677void MCAsmStreamer::emitThumbFunc(MCSymbol *Func) {
678 // This needs to emit to a temporary string to get properly quoted
679 // MCSymbols when they have spaces in them.
680 OS << "\t.thumb_func";
681 // Only Mach-O hasSubsectionsViaSymbols()
682 if (MAI->hasSubsectionsViaSymbols()) {
683 OS << '\t';
684 Func->print(OS, MAI);
685 }
686 EmitEOL();
687}
688
689void MCAsmStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
690 // Do not emit a .set on inlined target assignments.
691 bool EmitSet = true;
692 if (auto *E = dyn_cast<MCTargetExpr>(Val: Value))
693 if (E->inlineAssignedExpr())
694 EmitSet = false;
695 if (EmitSet) {
696 OS << ".set ";
697 Symbol->print(OS, MAI);
698 OS << ", ";
699 Value->print(OS, MAI);
700
701 EmitEOL();
702 }
703
704 MCStreamer::emitAssignment(Symbol, Value);
705}
706
707void MCAsmStreamer::emitConditionalAssignment(MCSymbol *Symbol,
708 const MCExpr *Value) {
709 OS << ".lto_set_conditional ";
710 Symbol->print(OS, MAI);
711 OS << ", ";
712 Value->print(OS, MAI);
713 EmitEOL();
714}
715
716void MCAsmStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
717 OS << ".weakref ";
718 Alias->print(OS, MAI);
719 OS << ", ";
720 Symbol->print(OS, MAI);
721 EmitEOL();
722}
723
724bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,
725 MCSymbolAttr Attribute) {
726 switch (Attribute) {
727 case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute");
728 case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function
729 case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC
730 case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object
731 case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object
732 case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common
733 case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype
734 case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object
735 if (!MAI->hasDotTypeDotSizeDirective())
736 return false; // Symbol attribute not supported
737 OS << "\t.type\t";
738 Symbol->print(OS, MAI);
739 OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%');
740 switch (Attribute) {
741 default: return false;
742 case MCSA_ELF_TypeFunction: OS << "function"; break;
743 case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;
744 case MCSA_ELF_TypeObject: OS << "object"; break;
745 case MCSA_ELF_TypeTLS: OS << "tls_object"; break;
746 case MCSA_ELF_TypeCommon: OS << "common"; break;
747 case MCSA_ELF_TypeNoType: OS << "notype"; break;
748 case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break;
749 }
750 EmitEOL();
751 return true;
752 case MCSA_Global: // .globl/.global
753 OS << MAI->getGlobalDirective();
754 break;
755 case MCSA_LGlobal: OS << "\t.lglobl\t"; break;
756 case MCSA_Hidden: OS << "\t.hidden\t"; break;
757 case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
758 case MCSA_Internal: OS << "\t.internal\t"; break;
759 case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break;
760 case MCSA_Local: OS << "\t.local\t"; break;
761 case MCSA_NoDeadStrip:
762 if (!MAI->hasNoDeadStrip())
763 return false;
764 OS << "\t.no_dead_strip\t";
765 break;
766 case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;
767 case MCSA_AltEntry: OS << "\t.alt_entry\t"; break;
768 case MCSA_PrivateExtern:
769 OS << "\t.private_extern\t";
770 break;
771 case MCSA_Protected: OS << "\t.protected\t"; break;
772 case MCSA_Reference: OS << "\t.reference\t"; break;
773 case MCSA_Extern:
774 OS << "\t.extern\t";
775 break;
776 case MCSA_Weak: OS << MAI->getWeakDirective(); break;
777 case MCSA_WeakDefinition:
778 OS << "\t.weak_definition\t";
779 break;
780 // .weak_reference
781 case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break;
782 case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break;
783 case MCSA_Cold:
784 // Assemblers currently do not support a .cold directive.
785 case MCSA_Exported:
786 // Non-AIX assemblers currently do not support exported visibility.
787 return false;
788 case MCSA_Memtag:
789 OS << "\t.memtag\t";
790 break;
791 case MCSA_WeakAntiDep:
792 OS << "\t.weak_anti_dep\t";
793 break;
794 }
795
796 Symbol->print(OS, MAI);
797 EmitEOL();
798
799 return true;
800}
801
802void MCAsmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
803 OS << ".desc" << ' ';
804 Symbol->print(OS, MAI);
805 OS << ',' << DescValue;
806 EmitEOL();
807}
808
809void MCAsmStreamer::emitSyntaxDirective() {
810 if (MAI->getAssemblerDialect() == 1) {
811 OS << "\t.intel_syntax noprefix";
812 EmitEOL();
813 }
814 // FIXME: Currently emit unprefix'ed registers.
815 // The intel_syntax directive has one optional argument
816 // with may have a value of prefix or noprefix.
817}
818
819void MCAsmStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {
820 OS << "\t.def\t";
821 Symbol->print(OS, MAI);
822 OS << ';';
823 EmitEOL();
824}
825
826void MCAsmStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
827 OS << "\t.scl\t" << StorageClass << ';';
828 EmitEOL();
829}
830
831void MCAsmStreamer::emitCOFFSymbolType(int Type) {
832 OS << "\t.type\t" << Type << ';';
833 EmitEOL();
834}
835
836void MCAsmStreamer::endCOFFSymbolDef() {
837 OS << "\t.endef";
838 EmitEOL();
839}
840
841void MCAsmStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {
842 OS << "\t.safeseh\t";
843 Symbol->print(OS, MAI);
844 EmitEOL();
845}
846
847void MCAsmStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
848 OS << "\t.symidx\t";
849 Symbol->print(OS, MAI);
850 EmitEOL();
851}
852
853void MCAsmStreamer::emitCOFFSectionIndex(MCSymbol const *Symbol) {
854 OS << "\t.secidx\t";
855 Symbol->print(OS, MAI);
856 EmitEOL();
857}
858
859void MCAsmStreamer::emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {
860 OS << "\t.secrel32\t";
861 Symbol->print(OS, MAI);
862 if (Offset != 0)
863 OS << '+' << Offset;
864 EmitEOL();
865}
866
867void MCAsmStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {
868 OS << "\t.rva\t";
869 Symbol->print(OS, MAI);
870 if (Offset > 0)
871 OS << '+' << Offset;
872 else if (Offset < 0)
873 OS << '-' << -Offset;
874 EmitEOL();
875}
876
877// We need an XCOFF-specific version of this directive as the AIX syntax
878// requires a QualName argument identifying the csect name and storage mapping
879// class to appear before the alignment if we are specifying it.
880void MCAsmStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
881 uint64_t Size,
882 MCSymbol *CsectSym,
883 Align Alignment) {
884 assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment &&
885 "We only support writing log base-2 alignment format with XCOFF.");
886
887 OS << "\t.lcomm\t";
888 LabelSym->print(OS, MAI);
889 OS << ',' << Size << ',';
890 CsectSym->print(OS, MAI);
891 OS << ',' << Log2(A: Alignment);
892
893 EmitEOL();
894
895 // Print symbol's rename (original name contains invalid character(s)) if
896 // there is one.
897 MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Val: CsectSym);
898 if (XSym->hasRename())
899 emitXCOFFRenameDirective(Name: XSym, Rename: XSym->getSymbolTableName());
900}
901
902void MCAsmStreamer::emitXCOFFSymbolLinkageWithVisibility(
903 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
904
905 switch (Linkage) {
906 case MCSA_Global:
907 OS << MAI->getGlobalDirective();
908 break;
909 case MCSA_Weak:
910 OS << MAI->getWeakDirective();
911 break;
912 case MCSA_Extern:
913 OS << "\t.extern\t";
914 break;
915 case MCSA_LGlobal:
916 OS << "\t.lglobl\t";
917 break;
918 default:
919 report_fatal_error(reason: "unhandled linkage type");
920 }
921
922 Symbol->print(OS, MAI);
923
924 switch (Visibility) {
925 case MCSA_Invalid:
926 // Nothing to do.
927 break;
928 case MCSA_Hidden:
929 OS << ",hidden";
930 break;
931 case MCSA_Protected:
932 OS << ",protected";
933 break;
934 case MCSA_Exported:
935 OS << ",exported";
936 break;
937 default:
938 report_fatal_error(reason: "unexpected value for Visibility type");
939 }
940 EmitEOL();
941
942 // Print symbol's rename (original name contains invalid character(s)) if
943 // there is one.
944 if (cast<MCSymbolXCOFF>(Val: Symbol)->hasRename())
945 emitXCOFFRenameDirective(Name: Symbol,
946 Rename: cast<MCSymbolXCOFF>(Val: Symbol)->getSymbolTableName());
947}
948
949void MCAsmStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
950 StringRef Rename) {
951 OS << "\t.rename\t";
952 Name->print(OS, MAI);
953 const char DQ = '"';
954 OS << ',' << DQ;
955 for (char C : Rename) {
956 // To escape a double quote character, the character should be doubled.
957 if (C == DQ)
958 OS << DQ;
959 OS << C;
960 }
961 OS << DQ;
962 EmitEOL();
963}
964
965void MCAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
966 OS << "\t.ref ";
967 Symbol->print(OS, MAI);
968 EmitEOL();
969}
970
971void MCAsmStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
972 const MCSymbol *Trap,
973 unsigned Lang,
974 unsigned Reason,
975 unsigned FunctionSize,
976 bool hasDebug) {
977 OS << "\t.except\t";
978 Symbol->print(OS, MAI);
979 OS << ", " << Lang << ", " << Reason;
980 EmitEOL();
981}
982
983void MCAsmStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
984 const char InfoDirective[] = "\t.info ";
985 const char *Separator = ", ";
986 constexpr int WordSize = sizeof(uint32_t);
987
988 // Start by emitting the .info pseudo-op and C_INFO symbol name.
989 OS << InfoDirective;
990 PrintQuotedString(Data: Name, OS);
991 OS << Separator;
992
993 size_t MetadataSize = Metadata.size();
994
995 // Emit the 4-byte length of the metadata.
996 OS << format_hex(N: MetadataSize, Width: 10) << Separator;
997
998 // Nothing left to do if there's no metadata.
999 if (MetadataSize == 0) {
1000 EmitEOL();
1001 return;
1002 }
1003
1004 // Metadata needs to be padded out to an even word size when generating
1005 // assembly because the .info pseudo-op can only generate words of data. We
1006 // apply the same restriction to the object case for consistency, however the
1007 // linker doesn't require padding, so it will only save bytes specified by the
1008 // length and discard any padding.
1009 uint32_t PaddedSize = alignTo(Value: MetadataSize, Align: WordSize);
1010 uint32_t PaddingSize = PaddedSize - MetadataSize;
1011
1012 // Write out the payload a word at a time.
1013 //
1014 // The assembler has a limit on the number of operands in an expression,
1015 // so we need multiple .info pseudo-ops. We choose a small number of words
1016 // per pseudo-op to keep the assembly readable.
1017 constexpr int WordsPerDirective = 5;
1018 // Force emitting a new directive to keep the first directive purely about the
1019 // name and size of the note.
1020 int WordsBeforeNextDirective = 0;
1021 auto PrintWord = [&](const uint8_t *WordPtr) {
1022 if (WordsBeforeNextDirective-- == 0) {
1023 EmitEOL();
1024 OS << InfoDirective;
1025 WordsBeforeNextDirective = WordsPerDirective;
1026 }
1027 OS << Separator;
1028 uint32_t Word = llvm::support::endian::read32be(P: WordPtr);
1029 OS << format_hex(N: Word, Width: 10);
1030 };
1031
1032 size_t Index = 0;
1033 for (; Index + WordSize <= MetadataSize; Index += WordSize)
1034 PrintWord(reinterpret_cast<const uint8_t *>(Metadata.data()) + Index);
1035
1036 // If there is padding, then we have at least one byte of payload left
1037 // to emit.
1038 if (PaddingSize) {
1039 assert(PaddedSize - Index == WordSize);
1040 std::array<uint8_t, WordSize> LastWord = {0};
1041 ::memcpy(dest: LastWord.data(), src: Metadata.data() + Index, n: MetadataSize - Index);
1042 PrintWord(LastWord.data());
1043 }
1044 EmitEOL();
1045}
1046
1047void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
1048 assert(MAI->hasDotTypeDotSizeDirective());
1049 OS << "\t.size\t";
1050 Symbol->print(OS, MAI);
1051 OS << ", ";
1052 Value->print(OS, MAI);
1053 EmitEOL();
1054}
1055
1056void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
1057 Align ByteAlignment) {
1058 OS << "\t.comm\t";
1059 Symbol->print(OS, MAI);
1060 OS << ',' << Size;
1061
1062 if (MAI->getCOMMDirectiveAlignmentIsInBytes())
1063 OS << ',' << ByteAlignment.value();
1064 else
1065 OS << ',' << Log2(A: ByteAlignment);
1066 EmitEOL();
1067
1068 // Print symbol's rename (original name contains invalid character(s)) if
1069 // there is one.
1070 MCSymbolXCOFF *XSym = dyn_cast<MCSymbolXCOFF>(Val: Symbol);
1071 if (XSym && XSym->hasRename())
1072 emitXCOFFRenameDirective(Name: XSym, Rename: XSym->getSymbolTableName());
1073}
1074
1075void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
1076 Align ByteAlign) {
1077 OS << "\t.lcomm\t";
1078 Symbol->print(OS, MAI);
1079 OS << ',' << Size;
1080
1081 if (ByteAlign > 1) {
1082 switch (MAI->getLCOMMDirectiveAlignmentType()) {
1083 case LCOMM::NoAlignment:
1084 llvm_unreachable("alignment not supported on .lcomm!");
1085 case LCOMM::ByteAlignment:
1086 OS << ',' << ByteAlign.value();
1087 break;
1088 case LCOMM::Log2Alignment:
1089 OS << ',' << Log2(A: ByteAlign);
1090 break;
1091 }
1092 }
1093 EmitEOL();
1094}
1095
1096void MCAsmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
1097 uint64_t Size, Align ByteAlignment,
1098 SMLoc Loc) {
1099 if (Symbol)
1100 Symbol->setFragment(&Section->getDummyFragment());
1101
1102 // Note: a .zerofill directive does not switch sections.
1103 OS << ".zerofill ";
1104
1105 assert(Section->getVariant() == MCSection::SV_MachO &&
1106 ".zerofill is a Mach-O specific directive");
1107 // This is a mach-o specific directive.
1108
1109 const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
1110 OS << MOSection->getSegmentName() << "," << MOSection->getName();
1111
1112 if (Symbol) {
1113 OS << ',';
1114 Symbol->print(OS, MAI);
1115 OS << ',' << Size;
1116 OS << ',' << Log2(A: ByteAlignment);
1117 }
1118 EmitEOL();
1119}
1120
1121// .tbss sym, size, align
1122// This depends that the symbol has already been mangled from the original,
1123// e.g. _a.
1124void MCAsmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
1125 uint64_t Size, Align ByteAlignment) {
1126 Symbol->setFragment(&Section->getDummyFragment());
1127
1128 // Instead of using the Section we'll just use the shortcut.
1129
1130 assert(Section->getVariant() == MCSection::SV_MachO &&
1131 ".zerofill is a Mach-O specific directive");
1132 // This is a mach-o specific directive and section.
1133
1134 OS << ".tbss ";
1135 Symbol->print(OS, MAI);
1136 OS << ", " << Size;
1137
1138 // Output align if we have it. We default to 1 so don't bother printing
1139 // that.
1140 if (ByteAlignment > 1)
1141 OS << ", " << Log2(A: ByteAlignment);
1142
1143 EmitEOL();
1144}
1145
1146static inline bool isPrintableString(StringRef Data) {
1147 const auto BeginPtr = Data.begin(), EndPtr = Data.end();
1148 for (const unsigned char C : make_range(x: BeginPtr, y: EndPtr - 1)) {
1149 if (!isPrint(C))
1150 return false;
1151 }
1152 return isPrint(C: Data.back()) || Data.back() == 0;
1153}
1154
1155static inline char toOctal(int X) { return (X&7)+'0'; }
1156
1157static void PrintByteList(StringRef Data, raw_ostream &OS,
1158 MCAsmInfo::AsmCharLiteralSyntax ACLS) {
1159 assert(!Data.empty() && "Cannot generate an empty list.");
1160 const auto printCharacterInOctal = [&OS](unsigned char C) {
1161 OS << '0';
1162 OS << toOctal(X: C >> 6);
1163 OS << toOctal(X: C >> 3);
1164 OS << toOctal(X: C >> 0);
1165 };
1166 const auto printOneCharacterFor = [printCharacterInOctal](
1167 auto printOnePrintingCharacter) {
1168 return [printCharacterInOctal, printOnePrintingCharacter](unsigned char C) {
1169 if (isPrint(C)) {
1170 printOnePrintingCharacter(static_cast<char>(C));
1171 return;
1172 }
1173 printCharacterInOctal(C);
1174 };
1175 };
1176 const auto printCharacterList = [Data, &OS](const auto &printOneCharacter) {
1177 const auto BeginPtr = Data.begin(), EndPtr = Data.end();
1178 for (const unsigned char C : make_range(x: BeginPtr, y: EndPtr - 1)) {
1179 printOneCharacter(C);
1180 OS << ',';
1181 }
1182 printOneCharacter(*(EndPtr - 1));
1183 };
1184 switch (ACLS) {
1185 case MCAsmInfo::ACLS_Unknown:
1186 printCharacterList(printCharacterInOctal);
1187 return;
1188 case MCAsmInfo::ACLS_SingleQuotePrefix:
1189 printCharacterList(printOneCharacterFor([&OS](char C) {
1190 const char AsmCharLitBuf[2] = {'\'', C};
1191 OS << StringRef(AsmCharLitBuf, sizeof(AsmCharLitBuf));
1192 }));
1193 return;
1194 }
1195 llvm_unreachable("Invalid AsmCharLiteralSyntax value!");
1196}
1197
1198void MCAsmStreamer::PrintQuotedString(StringRef Data, raw_ostream &OS) const {
1199 OS << '"';
1200
1201 if (MAI->hasPairedDoubleQuoteStringConstants()) {
1202 for (unsigned char C : Data) {
1203 if (C == '"')
1204 OS << "\"\"";
1205 else
1206 OS << (char)C;
1207 }
1208 } else {
1209 for (unsigned char C : Data) {
1210 if (C == '"' || C == '\\') {
1211 OS << '\\' << (char)C;
1212 continue;
1213 }
1214
1215 if (isPrint(C: (unsigned char)C)) {
1216 OS << (char)C;
1217 continue;
1218 }
1219
1220 switch (C) {
1221 case '\b':
1222 OS << "\\b";
1223 break;
1224 case '\f':
1225 OS << "\\f";
1226 break;
1227 case '\n':
1228 OS << "\\n";
1229 break;
1230 case '\r':
1231 OS << "\\r";
1232 break;
1233 case '\t':
1234 OS << "\\t";
1235 break;
1236 default:
1237 OS << '\\';
1238 OS << toOctal(X: C >> 6);
1239 OS << toOctal(X: C >> 3);
1240 OS << toOctal(X: C >> 0);
1241 break;
1242 }
1243 }
1244 }
1245
1246 OS << '"';
1247}
1248
1249void MCAsmStreamer::emitBytes(StringRef Data) {
1250 assert(getCurrentSectionOnly() &&
1251 "Cannot emit contents before setting section!");
1252 if (Data.empty()) return;
1253
1254 const auto emitAsString = [this](StringRef Data) {
1255 // If the data ends with 0 and the target supports .asciz, use it, otherwise
1256 // use .ascii or a byte-list directive
1257 if (MAI->getAscizDirective() && Data.back() == 0) {
1258 OS << MAI->getAscizDirective();
1259 Data = Data.substr(Start: 0, N: Data.size() - 1);
1260 } else if (LLVM_LIKELY(MAI->getAsciiDirective())) {
1261 OS << MAI->getAsciiDirective();
1262 } else if (MAI->hasPairedDoubleQuoteStringConstants() &&
1263 isPrintableString(Data)) {
1264 // For target with DoubleQuoteString constants, .string and .byte are used
1265 // as replacement of .asciz and .ascii.
1266 assert(MAI->getPlainStringDirective() &&
1267 "hasPairedDoubleQuoteStringConstants target must support "
1268 "PlainString Directive");
1269 assert(MAI->getByteListDirective() &&
1270 "hasPairedDoubleQuoteStringConstants target must support ByteList "
1271 "Directive");
1272 if (Data.back() == 0) {
1273 OS << MAI->getPlainStringDirective();
1274 Data = Data.substr(Start: 0, N: Data.size() - 1);
1275 } else {
1276 OS << MAI->getByteListDirective();
1277 }
1278 } else if (MAI->getByteListDirective()) {
1279 OS << MAI->getByteListDirective();
1280 PrintByteList(Data, OS, ACLS: MAI->characterLiteralSyntax());
1281 EmitEOL();
1282 return true;
1283 } else {
1284 return false;
1285 }
1286
1287 PrintQuotedString(Data, OS);
1288 EmitEOL();
1289 return true;
1290 };
1291
1292 if (Data.size() != 1 && emitAsString(Data))
1293 return;
1294
1295 // Only single byte is provided or no ascii, asciz, or byte-list directives
1296 // are applicable. Emit as vector of individual 8bits data elements.
1297 if (MCTargetStreamer *TS = getTargetStreamer()) {
1298 TS->emitRawBytes(Data);
1299 return;
1300 }
1301 const char *Directive = MAI->getData8bitsDirective();
1302 for (const unsigned char C : Data.bytes()) {
1303 OS << Directive << (unsigned)C;
1304 EmitEOL();
1305 }
1306}
1307
1308void MCAsmStreamer::emitBinaryData(StringRef Data) {
1309 // This is binary data. Print it in a grid of hex bytes for readability.
1310 const size_t Cols = 4;
1311 for (size_t I = 0, EI = alignTo(Value: Data.size(), Align: Cols); I < EI; I += Cols) {
1312 size_t J = I, EJ = std::min(a: I + Cols, b: Data.size());
1313 assert(EJ > 0);
1314 OS << MAI->getData8bitsDirective();
1315 for (; J < EJ - 1; ++J)
1316 OS << format(Fmt: "0x%02x", Vals: uint8_t(Data[J])) << ", ";
1317 OS << format(Fmt: "0x%02x", Vals: uint8_t(Data[J]));
1318 EmitEOL();
1319 }
1320}
1321
1322void MCAsmStreamer::emitIntValue(uint64_t Value, unsigned Size) {
1323 emitValue(Value: MCConstantExpr::create(Value, Ctx&: getContext()), Size);
1324}
1325
1326void MCAsmStreamer::emitIntValueInHex(uint64_t Value, unsigned Size) {
1327 emitValue(Value: MCConstantExpr::create(Value, Ctx&: getContext(), PrintInHex: true), Size);
1328}
1329
1330void MCAsmStreamer::emitIntValueInHexWithPadding(uint64_t Value,
1331 unsigned Size) {
1332 emitValue(Value: MCConstantExpr::create(Value, Ctx&: getContext(), PrintInHex: true, SizeInBytes: Size), Size);
1333}
1334
1335void MCAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
1336 SMLoc Loc) {
1337 assert(Size <= 8 && "Invalid size");
1338 assert(getCurrentSectionOnly() &&
1339 "Cannot emit contents before setting section!");
1340 const char *Directive = nullptr;
1341 switch (Size) {
1342 default: break;
1343 case 1: Directive = MAI->getData8bitsDirective(); break;
1344 case 2: Directive = MAI->getData16bitsDirective(); break;
1345 case 4: Directive = MAI->getData32bitsDirective(); break;
1346 case 8: Directive = MAI->getData64bitsDirective(); break;
1347 }
1348
1349 if (!Directive) {
1350 int64_t IntValue;
1351 if (!Value->evaluateAsAbsolute(Res&: IntValue))
1352 report_fatal_error(reason: "Don't know how to emit this value.");
1353
1354 // We couldn't handle the requested integer size so we fallback by breaking
1355 // the request down into several, smaller, integers.
1356 // Since sizes greater or equal to "Size" are invalid, we use the greatest
1357 // power of 2 that is less than "Size" as our largest piece of granularity.
1358 bool IsLittleEndian = MAI->isLittleEndian();
1359 for (unsigned Emitted = 0; Emitted != Size;) {
1360 unsigned Remaining = Size - Emitted;
1361 // The size of our partial emission must be a power of two less than
1362 // Size.
1363 unsigned EmissionSize = llvm::bit_floor(Value: std::min(a: Remaining, b: Size - 1));
1364 // Calculate the byte offset of our partial emission taking into account
1365 // the endianness of the target.
1366 unsigned ByteOffset =
1367 IsLittleEndian ? Emitted : (Remaining - EmissionSize);
1368 uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);
1369 // We truncate our partial emission to fit within the bounds of the
1370 // emission domain. This produces nicer output and silences potential
1371 // truncation warnings when round tripping through another assembler.
1372 uint64_t Shift = 64 - EmissionSize * 8;
1373 assert(Shift < static_cast<uint64_t>(
1374 std::numeric_limits<unsigned long long>::digits) &&
1375 "undefined behavior");
1376 ValueToEmit &= ~0ULL >> Shift;
1377 emitIntValue(Value: ValueToEmit, Size: EmissionSize);
1378 Emitted += EmissionSize;
1379 }
1380 return;
1381 }
1382
1383 assert(Directive && "Invalid size for machine code value!");
1384 OS << Directive;
1385 if (MCTargetStreamer *TS = getTargetStreamer()) {
1386 TS->emitValue(Value);
1387 } else {
1388 Value->print(OS, MAI);
1389 EmitEOL();
1390 }
1391}
1392
1393void MCAsmStreamer::emitULEB128Value(const MCExpr *Value) {
1394 int64_t IntValue;
1395 if (Value->evaluateAsAbsolute(Res&: IntValue)) {
1396 emitULEB128IntValue(Value: IntValue);
1397 return;
1398 }
1399 OS << "\t.uleb128 ";
1400 Value->print(OS, MAI);
1401 EmitEOL();
1402}
1403
1404void MCAsmStreamer::emitSLEB128Value(const MCExpr *Value) {
1405 int64_t IntValue;
1406 if (Value->evaluateAsAbsolute(Res&: IntValue)) {
1407 emitSLEB128IntValue(Value: IntValue);
1408 return;
1409 }
1410 OS << "\t.sleb128 ";
1411 Value->print(OS, MAI);
1412 EmitEOL();
1413}
1414
1415void MCAsmStreamer::emitDTPRel64Value(const MCExpr *Value) {
1416 assert(MAI->getDTPRel64Directive() != nullptr);
1417 OS << MAI->getDTPRel64Directive();
1418 Value->print(OS, MAI);
1419 EmitEOL();
1420}
1421
1422void MCAsmStreamer::emitDTPRel32Value(const MCExpr *Value) {
1423 assert(MAI->getDTPRel32Directive() != nullptr);
1424 OS << MAI->getDTPRel32Directive();
1425 Value->print(OS, MAI);
1426 EmitEOL();
1427}
1428
1429void MCAsmStreamer::emitTPRel64Value(const MCExpr *Value) {
1430 assert(MAI->getTPRel64Directive() != nullptr);
1431 OS << MAI->getTPRel64Directive();
1432 Value->print(OS, MAI);
1433 EmitEOL();
1434}
1435
1436void MCAsmStreamer::emitTPRel32Value(const MCExpr *Value) {
1437 assert(MAI->getTPRel32Directive() != nullptr);
1438 OS << MAI->getTPRel32Directive();
1439 Value->print(OS, MAI);
1440 EmitEOL();
1441}
1442
1443void MCAsmStreamer::emitGPRel64Value(const MCExpr *Value) {
1444 assert(MAI->getGPRel64Directive() != nullptr);
1445 OS << MAI->getGPRel64Directive();
1446 Value->print(OS, MAI);
1447 EmitEOL();
1448}
1449
1450void MCAsmStreamer::emitGPRel32Value(const MCExpr *Value) {
1451 assert(MAI->getGPRel32Directive() != nullptr);
1452 OS << MAI->getGPRel32Directive();
1453 Value->print(OS, MAI);
1454 EmitEOL();
1455}
1456
1457void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
1458 SMLoc Loc) {
1459 int64_t IntNumBytes;
1460 const bool IsAbsolute = NumBytes.evaluateAsAbsolute(Res&: IntNumBytes);
1461 if (IsAbsolute && IntNumBytes == 0)
1462 return;
1463
1464 if (const char *ZeroDirective = MAI->getZeroDirective()) {
1465 if (MAI->doesZeroDirectiveSupportNonZeroValue() || FillValue == 0) {
1466 // FIXME: Emit location directives
1467 OS << ZeroDirective;
1468 NumBytes.print(OS, MAI);
1469 if (FillValue != 0)
1470 OS << ',' << (int)FillValue;
1471 EmitEOL();
1472 } else {
1473 if (!IsAbsolute)
1474 report_fatal_error(
1475 reason: "Cannot emit non-absolute expression lengths of fill.");
1476 for (int i = 0; i < IntNumBytes; ++i) {
1477 OS << MAI->getData8bitsDirective() << (int)FillValue;
1478 EmitEOL();
1479 }
1480 }
1481 return;
1482 }
1483
1484 MCStreamer::emitFill(NumBytes, FillValue);
1485}
1486
1487void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
1488 int64_t Expr, SMLoc Loc) {
1489 // FIXME: Emit location directives
1490 OS << "\t.fill\t";
1491 NumValues.print(OS, MAI);
1492 OS << ", " << Size << ", 0x";
1493 OS.write_hex(N: truncateToSize(Value: Expr, Bytes: 4));
1494 EmitEOL();
1495}
1496
1497void MCAsmStreamer::emitAlignmentDirective(uint64_t ByteAlignment,
1498 std::optional<int64_t> Value,
1499 unsigned ValueSize,
1500 unsigned MaxBytesToEmit) {
1501 if (MAI->useDotAlignForAlignment()) {
1502 if (!isPowerOf2_64(Value: ByteAlignment))
1503 report_fatal_error(reason: "Only power-of-two alignments are supported "
1504 "with .align.");
1505 OS << "\t.align\t";
1506 OS << Log2_64(Value: ByteAlignment);
1507 EmitEOL();
1508 return;
1509 }
1510
1511 // Some assemblers don't support non-power of two alignments, so we always
1512 // emit alignments as a power of two if possible.
1513 if (isPowerOf2_64(Value: ByteAlignment)) {
1514 switch (ValueSize) {
1515 default:
1516 llvm_unreachable("Invalid size for machine code value!");
1517 case 1:
1518 OS << "\t.p2align\t";
1519 break;
1520 case 2:
1521 OS << ".p2alignw ";
1522 break;
1523 case 4:
1524 OS << ".p2alignl ";
1525 break;
1526 case 8:
1527 llvm_unreachable("Unsupported alignment size!");
1528 }
1529
1530 OS << Log2_64(Value: ByteAlignment);
1531
1532 if (Value.has_value() || MaxBytesToEmit) {
1533 if (Value.has_value()) {
1534 OS << ", 0x";
1535 OS.write_hex(N: truncateToSize(Value: *Value, Bytes: ValueSize));
1536 } else {
1537 OS << ", ";
1538 }
1539
1540 if (MaxBytesToEmit)
1541 OS << ", " << MaxBytesToEmit;
1542 }
1543 EmitEOL();
1544 return;
1545 }
1546
1547 // Non-power of two alignment. This is not widely supported by assemblers.
1548 // FIXME: Parameterize this based on MAI.
1549 switch (ValueSize) {
1550 default: llvm_unreachable("Invalid size for machine code value!");
1551 case 1: OS << ".balign"; break;
1552 case 2: OS << ".balignw"; break;
1553 case 4: OS << ".balignl"; break;
1554 case 8: llvm_unreachable("Unsupported alignment size!");
1555 }
1556
1557 OS << ' ' << ByteAlignment;
1558 if (Value.has_value())
1559 OS << ", " << truncateToSize(Value: *Value, Bytes: ValueSize);
1560 else if (MaxBytesToEmit)
1561 OS << ", ";
1562 if (MaxBytesToEmit)
1563 OS << ", " << MaxBytesToEmit;
1564 EmitEOL();
1565}
1566
1567void MCAsmStreamer::emitValueToAlignment(Align Alignment, int64_t Value,
1568 unsigned ValueSize,
1569 unsigned MaxBytesToEmit) {
1570 emitAlignmentDirective(ByteAlignment: Alignment.value(), Value, ValueSize, MaxBytesToEmit);
1571}
1572
1573void MCAsmStreamer::emitCodeAlignment(Align Alignment,
1574 const MCSubtargetInfo *STI,
1575 unsigned MaxBytesToEmit) {
1576 // Emit with a text fill value.
1577 if (MAI->getTextAlignFillValue())
1578 emitAlignmentDirective(ByteAlignment: Alignment.value(), Value: MAI->getTextAlignFillValue(), ValueSize: 1,
1579 MaxBytesToEmit);
1580 else
1581 emitAlignmentDirective(ByteAlignment: Alignment.value(), Value: std::nullopt, ValueSize: 1, MaxBytesToEmit);
1582}
1583
1584void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,
1585 unsigned char Value,
1586 SMLoc Loc) {
1587 // FIXME: Verify that Offset is associated with the current section.
1588 OS << ".org ";
1589 Offset->print(OS, MAI);
1590 OS << ", " << (unsigned)Value;
1591 EmitEOL();
1592}
1593
1594void MCAsmStreamer::emitFileDirective(StringRef Filename) {
1595 assert(MAI->hasSingleParameterDotFile());
1596 OS << "\t.file\t";
1597 PrintQuotedString(Data: Filename, OS);
1598 EmitEOL();
1599}
1600
1601void MCAsmStreamer::emitFileDirective(StringRef Filename,
1602 StringRef CompilerVersion,
1603 StringRef TimeStamp,
1604 StringRef Description) {
1605 assert(MAI->hasFourStringsDotFile());
1606 OS << "\t.file\t";
1607 PrintQuotedString(Data: Filename, OS);
1608 bool useTimeStamp = !TimeStamp.empty();
1609 bool useCompilerVersion = !CompilerVersion.empty();
1610 bool useDescription = !Description.empty();
1611 if (useTimeStamp || useCompilerVersion || useDescription) {
1612 OS << ",";
1613 if (useTimeStamp)
1614 PrintQuotedString(Data: TimeStamp, OS);
1615 if (useCompilerVersion || useDescription) {
1616 OS << ",";
1617 if (useCompilerVersion)
1618 PrintQuotedString(Data: CompilerVersion, OS);
1619 if (useDescription) {
1620 OS << ",";
1621 PrintQuotedString(Data: Description, OS);
1622 }
1623 }
1624 }
1625 EmitEOL();
1626}
1627
1628void MCAsmStreamer::printDwarfFileDirective(
1629 unsigned FileNo, StringRef Directory, StringRef Filename,
1630 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
1631 bool UseDwarfDirectory, raw_svector_ostream &OS) const {
1632 SmallString<128> FullPathName;
1633
1634 if (!UseDwarfDirectory && !Directory.empty()) {
1635 if (sys::path::is_absolute(path: Filename))
1636 Directory = "";
1637 else {
1638 FullPathName = Directory;
1639 sys::path::append(path&: FullPathName, a: Filename);
1640 Directory = "";
1641 Filename = FullPathName;
1642 }
1643 }
1644
1645 OS << "\t.file\t" << FileNo << ' ';
1646 if (!Directory.empty()) {
1647 PrintQuotedString(Data: Directory, OS);
1648 OS << ' ';
1649 }
1650 PrintQuotedString(Data: Filename, OS);
1651 if (Checksum)
1652 OS << " md5 0x" << Checksum->digest();
1653 if (Source) {
1654 OS << " source ";
1655 PrintQuotedString(Data: *Source, OS);
1656 }
1657}
1658
1659Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective(
1660 unsigned FileNo, StringRef Directory, StringRef Filename,
1661 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
1662 unsigned CUID) {
1663 assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer");
1664
1665 MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
1666 unsigned NumFiles = Table.getMCDwarfFiles().size();
1667 Expected<unsigned> FileNoOrErr =
1668 Table.tryGetFile(Directory, FileName&: Filename, Checksum, Source,
1669 DwarfVersion: getContext().getDwarfVersion(), FileNumber: FileNo);
1670 if (!FileNoOrErr)
1671 return FileNoOrErr.takeError();
1672 FileNo = FileNoOrErr.get();
1673
1674 // Return early if this file is already emitted before or if target doesn't
1675 // support .file directive.
1676 if (NumFiles == Table.getMCDwarfFiles().size() ||
1677 !MAI->usesDwarfFileAndLocDirectives())
1678 return FileNo;
1679
1680 SmallString<128> Str;
1681 raw_svector_ostream OS1(Str);
1682 printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source,
1683 UseDwarfDirectory, OS&: OS1);
1684
1685 if (MCTargetStreamer *TS = getTargetStreamer())
1686 TS->emitDwarfFileDirective(Directive: OS1.str());
1687 else
1688 emitRawText(String: OS1.str());
1689
1690 return FileNo;
1691}
1692
1693void MCAsmStreamer::emitDwarfFile0Directive(
1694 StringRef Directory, StringRef Filename,
1695 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
1696 unsigned CUID) {
1697 assert(CUID == 0);
1698 // .file 0 is new for DWARF v5.
1699 if (getContext().getDwarfVersion() < 5)
1700 return;
1701 // Inform MCDwarf about the root file.
1702 getContext().setMCLineTableRootFile(CUID, CompilationDir: Directory, Filename, Checksum,
1703 Source);
1704
1705 // Target doesn't support .loc/.file directives, return early.
1706 if (!MAI->usesDwarfFileAndLocDirectives())
1707 return;
1708
1709 SmallString<128> Str;
1710 raw_svector_ostream OS1(Str);
1711 printDwarfFileDirective(FileNo: 0, Directory, Filename, Checksum, Source,
1712 UseDwarfDirectory, OS&: OS1);
1713
1714 if (MCTargetStreamer *TS = getTargetStreamer())
1715 TS->emitDwarfFileDirective(Directive: OS1.str());
1716 else
1717 emitRawText(String: OS1.str());
1718}
1719
1720void MCAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
1721 unsigned Column, unsigned Flags,
1722 unsigned Isa, unsigned Discriminator,
1723 StringRef FileName) {
1724 // If target doesn't support .loc/.file directive, we need to record the lines
1725 // same way like we do in object mode.
1726 if (!MAI->usesDwarfFileAndLocDirectives()) {
1727 // In case we see two .loc directives in a row, make sure the
1728 // first one gets a line entry.
1729 MCDwarfLineEntry::make(MCOS: this, Section: getCurrentSectionOnly());
1730 this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
1731 Discriminator, FileName);
1732 return;
1733 }
1734
1735 OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
1736 if (MAI->supportsExtendedDwarfLocDirective()) {
1737 if (Flags & DWARF2_FLAG_BASIC_BLOCK)
1738 OS << " basic_block";
1739 if (Flags & DWARF2_FLAG_PROLOGUE_END)
1740 OS << " prologue_end";
1741 if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN)
1742 OS << " epilogue_begin";
1743
1744 unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags();
1745 if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) {
1746 OS << " is_stmt ";
1747
1748 if (Flags & DWARF2_FLAG_IS_STMT)
1749 OS << "1";
1750 else
1751 OS << "0";
1752 }
1753
1754 if (Isa)
1755 OS << " isa " << Isa;
1756 if (Discriminator)
1757 OS << " discriminator " << Discriminator;
1758 }
1759
1760 if (IsVerboseAsm) {
1761 OS.PadToColumn(NewCol: MAI->getCommentColumn());
1762 OS << MAI->getCommentString() << ' ' << FileName << ':'
1763 << Line << ':' << Column;
1764 }
1765 EmitEOL();
1766 this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
1767 Discriminator, FileName);
1768}
1769
1770MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
1771 // Always use the zeroth line table, since asm syntax only supports one line
1772 // table for now.
1773 return MCStreamer::getDwarfLineTableSymbol(CUID: 0);
1774}
1775
1776bool MCAsmStreamer::emitCVFileDirective(unsigned FileNo, StringRef Filename,
1777 ArrayRef<uint8_t> Checksum,
1778 unsigned ChecksumKind) {
1779 if (!getContext().getCVContext().addFile(OS&: *this, FileNumber: FileNo, Filename, ChecksumBytes: Checksum,
1780 ChecksumKind))
1781 return false;
1782
1783 OS << "\t.cv_file\t" << FileNo << ' ';
1784 PrintQuotedString(Data: Filename, OS);
1785
1786 if (!ChecksumKind) {
1787 EmitEOL();
1788 return true;
1789 }
1790
1791 OS << ' ';
1792 PrintQuotedString(Data: toHex(Input: Checksum), OS);
1793 OS << ' ' << ChecksumKind;
1794
1795 EmitEOL();
1796 return true;
1797}
1798
1799bool MCAsmStreamer::emitCVFuncIdDirective(unsigned FuncId) {
1800 OS << "\t.cv_func_id " << FuncId << '\n';
1801 return MCStreamer::emitCVFuncIdDirective(FunctionId: FuncId);
1802}
1803
1804bool MCAsmStreamer::emitCVInlineSiteIdDirective(unsigned FunctionId,
1805 unsigned IAFunc,
1806 unsigned IAFile,
1807 unsigned IALine, unsigned IACol,
1808 SMLoc Loc) {
1809 OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
1810 << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
1811 return MCStreamer::emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
1812 IALine, IACol, Loc);
1813}
1814
1815void MCAsmStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
1816 unsigned Line, unsigned Column,
1817 bool PrologueEnd, bool IsStmt,
1818 StringRef FileName, SMLoc Loc) {
1819 // Validate the directive.
1820 if (!checkCVLocSection(FuncId: FunctionId, FileNo, Loc))
1821 return;
1822
1823 OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
1824 << Column;
1825 if (PrologueEnd)
1826 OS << " prologue_end";
1827
1828 if (IsStmt)
1829 OS << " is_stmt 1";
1830
1831 if (IsVerboseAsm) {
1832 OS.PadToColumn(NewCol: MAI->getCommentColumn());
1833 OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
1834 << Column;
1835 }
1836 EmitEOL();
1837}
1838
1839void MCAsmStreamer::emitCVLinetableDirective(unsigned FunctionId,
1840 const MCSymbol *FnStart,
1841 const MCSymbol *FnEnd) {
1842 OS << "\t.cv_linetable\t" << FunctionId << ", ";
1843 FnStart->print(OS, MAI);
1844 OS << ", ";
1845 FnEnd->print(OS, MAI);
1846 EmitEOL();
1847 this->MCStreamer::emitCVLinetableDirective(FunctionId, FnStart, FnEnd);
1848}
1849
1850void MCAsmStreamer::emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
1851 unsigned SourceFileId,
1852 unsigned SourceLineNum,
1853 const MCSymbol *FnStartSym,
1854 const MCSymbol *FnEndSym) {
1855 OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
1856 << ' ' << SourceLineNum << ' ';
1857 FnStartSym->print(OS, MAI);
1858 OS << ' ';
1859 FnEndSym->print(OS, MAI);
1860 EmitEOL();
1861 this->MCStreamer::emitCVInlineLinetableDirective(
1862 PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
1863}
1864
1865void MCAsmStreamer::PrintCVDefRangePrefix(
1866 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) {
1867 OS << "\t.cv_def_range\t";
1868 for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
1869 OS << ' ';
1870 Range.first->print(OS, MAI);
1871 OS << ' ';
1872 Range.second->print(OS, MAI);
1873 }
1874}
1875
1876void MCAsmStreamer::emitCVDefRangeDirective(
1877 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
1878 codeview::DefRangeRegisterRelHeader DRHdr) {
1879 PrintCVDefRangePrefix(Ranges);
1880 OS << ", reg_rel, ";
1881 OS << DRHdr.Register << ", " << DRHdr.Flags << ", "
1882 << DRHdr.BasePointerOffset;
1883 EmitEOL();
1884}
1885
1886void MCAsmStreamer::emitCVDefRangeDirective(
1887 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
1888 codeview::DefRangeSubfieldRegisterHeader DRHdr) {
1889 PrintCVDefRangePrefix(Ranges);
1890 OS << ", subfield_reg, ";
1891 OS << DRHdr.Register << ", " << DRHdr.OffsetInParent;
1892 EmitEOL();
1893}
1894
1895void MCAsmStreamer::emitCVDefRangeDirective(
1896 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
1897 codeview::DefRangeRegisterHeader DRHdr) {
1898 PrintCVDefRangePrefix(Ranges);
1899 OS << ", reg, ";
1900 OS << DRHdr.Register;
1901 EmitEOL();
1902}
1903
1904void MCAsmStreamer::emitCVDefRangeDirective(
1905 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
1906 codeview::DefRangeFramePointerRelHeader DRHdr) {
1907 PrintCVDefRangePrefix(Ranges);
1908 OS << ", frame_ptr_rel, ";
1909 OS << DRHdr.Offset;
1910 EmitEOL();
1911}
1912
1913void MCAsmStreamer::emitCVStringTableDirective() {
1914 OS << "\t.cv_stringtable";
1915 EmitEOL();
1916}
1917
1918void MCAsmStreamer::emitCVFileChecksumsDirective() {
1919 OS << "\t.cv_filechecksums";
1920 EmitEOL();
1921}
1922
1923void MCAsmStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
1924 OS << "\t.cv_filechecksumoffset\t" << FileNo;
1925 EmitEOL();
1926}
1927
1928void MCAsmStreamer::emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
1929 OS << "\t.cv_fpo_data\t";
1930 ProcSym->print(OS, MAI);
1931 EmitEOL();
1932}
1933
1934void MCAsmStreamer::emitIdent(StringRef IdentString) {
1935 assert(MAI->hasIdentDirective() && ".ident directive not supported");
1936 OS << "\t.ident\t";
1937 PrintQuotedString(Data: IdentString, OS);
1938 EmitEOL();
1939}
1940
1941void MCAsmStreamer::emitCFISections(bool EH, bool Debug) {
1942 MCStreamer::emitCFISections(EH, Debug);
1943 OS << "\t.cfi_sections ";
1944 if (EH) {
1945 OS << ".eh_frame";
1946 if (Debug)
1947 OS << ", .debug_frame";
1948 } else if (Debug) {
1949 OS << ".debug_frame";
1950 }
1951
1952 EmitEOL();
1953}
1954
1955void MCAsmStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
1956 OS << "\t.cfi_startproc";
1957 if (Frame.IsSimple)
1958 OS << " simple";
1959 EmitEOL();
1960}
1961
1962void MCAsmStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
1963 MCStreamer::emitCFIEndProcImpl(CurFrame&: Frame);
1964 OS << "\t.cfi_endproc";
1965 EmitEOL();
1966}
1967
1968void MCAsmStreamer::EmitRegisterName(int64_t Register) {
1969 if (!MAI->useDwarfRegNumForCFI()) {
1970 // User .cfi_* directives can use arbitrary DWARF register numbers, not
1971 // just ones that map to LLVM register numbers and have known names.
1972 // Fall back to using the original number directly if no name is known.
1973 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
1974 if (std::optional<unsigned> LLVMRegister =
1975 MRI->getLLVMRegNum(RegNum: Register, isEH: true)) {
1976 InstPrinter->printRegName(OS, Reg: *LLVMRegister);
1977 return;
1978 }
1979 }
1980 OS << Register;
1981}
1982
1983void MCAsmStreamer::emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) {
1984 MCStreamer::emitCFIDefCfa(Register, Offset, Loc);
1985 OS << "\t.cfi_def_cfa ";
1986 EmitRegisterName(Register);
1987 OS << ", " << Offset;
1988 EmitEOL();
1989}
1990
1991void MCAsmStreamer::emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) {
1992 MCStreamer::emitCFIDefCfaOffset(Offset, Loc);
1993 OS << "\t.cfi_def_cfa_offset " << Offset;
1994 EmitEOL();
1995}
1996
1997void MCAsmStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
1998 int64_t AddressSpace, SMLoc Loc) {
1999 MCStreamer::emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace, Loc);
2000 OS << "\t.cfi_llvm_def_aspace_cfa ";
2001 EmitRegisterName(Register);
2002 OS << ", " << Offset;
2003 OS << ", " << AddressSpace;
2004 EmitEOL();
2005}
2006
2007static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
2008 OS << "\t.cfi_escape ";
2009 if (!Values.empty()) {
2010 size_t e = Values.size() - 1;
2011 for (size_t i = 0; i < e; ++i)
2012 OS << format(Fmt: "0x%02x", Vals: uint8_t(Values[i])) << ", ";
2013 OS << format(Fmt: "0x%02x", Vals: uint8_t(Values[e]));
2014 }
2015}
2016
2017void MCAsmStreamer::emitCFIEscape(StringRef Values, SMLoc Loc) {
2018 MCStreamer::emitCFIEscape(Values, Loc);
2019 PrintCFIEscape(OS, Values);
2020 EmitEOL();
2021}
2022
2023void MCAsmStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) {
2024 MCStreamer::emitCFIGnuArgsSize(Size, Loc);
2025
2026 uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };
2027 unsigned Len = encodeULEB128(Value: Size, p: Buffer + 1) + 1;
2028
2029 PrintCFIEscape(OS, Values: StringRef((const char *)&Buffer[0], Len));
2030 EmitEOL();
2031}
2032
2033void MCAsmStreamer::emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) {
2034 MCStreamer::emitCFIDefCfaRegister(Register, Loc);
2035 OS << "\t.cfi_def_cfa_register ";
2036 EmitRegisterName(Register);
2037 EmitEOL();
2038}
2039
2040void MCAsmStreamer::emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) {
2041 MCStreamer::emitCFIOffset(Register, Offset, Loc);
2042 OS << "\t.cfi_offset ";
2043 EmitRegisterName(Register);
2044 OS << ", " << Offset;
2045 EmitEOL();
2046}
2047
2048void MCAsmStreamer::emitCFIPersonality(const MCSymbol *Sym,
2049 unsigned Encoding) {
2050 MCStreamer::emitCFIPersonality(Sym, Encoding);
2051 OS << "\t.cfi_personality " << Encoding << ", ";
2052 Sym->print(OS, MAI);
2053 EmitEOL();
2054}
2055
2056void MCAsmStreamer::emitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
2057 MCStreamer::emitCFILsda(Sym, Encoding);
2058 OS << "\t.cfi_lsda " << Encoding << ", ";
2059 Sym->print(OS, MAI);
2060 EmitEOL();
2061}
2062
2063void MCAsmStreamer::emitCFIRememberState(SMLoc Loc) {
2064 MCStreamer::emitCFIRememberState(Loc);
2065 OS << "\t.cfi_remember_state";
2066 EmitEOL();
2067}
2068
2069void MCAsmStreamer::emitCFIRestoreState(SMLoc Loc) {
2070 MCStreamer::emitCFIRestoreState(Loc);
2071 OS << "\t.cfi_restore_state";
2072 EmitEOL();
2073}
2074
2075void MCAsmStreamer::emitCFIRestore(int64_t Register, SMLoc Loc) {
2076 MCStreamer::emitCFIRestore(Register, Loc);
2077 OS << "\t.cfi_restore ";
2078 EmitRegisterName(Register);
2079 EmitEOL();
2080}
2081
2082void MCAsmStreamer::emitCFISameValue(int64_t Register, SMLoc Loc) {
2083 MCStreamer::emitCFISameValue(Register, Loc);
2084 OS << "\t.cfi_same_value ";
2085 EmitRegisterName(Register);
2086 EmitEOL();
2087}
2088
2089void MCAsmStreamer::emitCFIRelOffset(int64_t Register, int64_t Offset,
2090 SMLoc Loc) {
2091 MCStreamer::emitCFIRelOffset(Register, Offset, Loc);
2092 OS << "\t.cfi_rel_offset ";
2093 EmitRegisterName(Register);
2094 OS << ", " << Offset;
2095 EmitEOL();
2096}
2097
2098void MCAsmStreamer::emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) {
2099 MCStreamer::emitCFIAdjustCfaOffset(Adjustment, Loc);
2100 OS << "\t.cfi_adjust_cfa_offset " << Adjustment;
2101 EmitEOL();
2102}
2103
2104void MCAsmStreamer::emitCFISignalFrame() {
2105 MCStreamer::emitCFISignalFrame();
2106 OS << "\t.cfi_signal_frame";
2107 EmitEOL();
2108}
2109
2110void MCAsmStreamer::emitCFIUndefined(int64_t Register, SMLoc Loc) {
2111 MCStreamer::emitCFIUndefined(Register, Loc);
2112 OS << "\t.cfi_undefined ";
2113 EmitRegisterName(Register);
2114 EmitEOL();
2115}
2116
2117void MCAsmStreamer::emitCFIRegister(int64_t Register1, int64_t Register2,
2118 SMLoc Loc) {
2119 MCStreamer::emitCFIRegister(Register1, Register2, Loc);
2120 OS << "\t.cfi_register ";
2121 EmitRegisterName(Register: Register1);
2122 OS << ", ";
2123 EmitRegisterName(Register: Register2);
2124 EmitEOL();
2125}
2126
2127void MCAsmStreamer::emitCFIWindowSave(SMLoc Loc) {
2128 MCStreamer::emitCFIWindowSave(Loc);
2129 OS << "\t.cfi_window_save";
2130 EmitEOL();
2131}
2132
2133void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
2134 MCStreamer::emitCFINegateRAState(Loc);
2135 OS << "\t.cfi_negate_ra_state";
2136 EmitEOL();
2137}
2138
2139void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
2140 MCStreamer::emitCFIReturnColumn(Register);
2141 OS << "\t.cfi_return_column ";
2142 EmitRegisterName(Register);
2143 EmitEOL();
2144}
2145
2146void MCAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
2147 MCStreamer::emitCFILabelDirective(Loc, Name);
2148 OS << "\t.cfi_label " << Name;
2149 EmitEOL();
2150}
2151
2152void MCAsmStreamer::emitCFIBKeyFrame() {
2153 MCStreamer::emitCFIBKeyFrame();
2154 OS << "\t.cfi_b_key_frame";
2155 EmitEOL();
2156}
2157
2158void MCAsmStreamer::emitCFIMTETaggedFrame() {
2159 MCStreamer::emitCFIMTETaggedFrame();
2160 OS << "\t.cfi_mte_tagged_frame";
2161 EmitEOL();
2162}
2163
2164void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
2165 MCStreamer::emitWinCFIStartProc(Symbol, Loc);
2166
2167 OS << ".seh_proc ";
2168 Symbol->print(OS, MAI);
2169 EmitEOL();
2170}
2171
2172void MCAsmStreamer::emitWinCFIEndProc(SMLoc Loc) {
2173 MCStreamer::emitWinCFIEndProc(Loc);
2174
2175 OS << "\t.seh_endproc";
2176 EmitEOL();
2177}
2178
2179void MCAsmStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
2180 MCStreamer::emitWinCFIFuncletOrFuncEnd(Loc);
2181
2182 OS << "\t.seh_endfunclet";
2183 EmitEOL();
2184}
2185
2186void MCAsmStreamer::emitWinCFIStartChained(SMLoc Loc) {
2187 MCStreamer::emitWinCFIStartChained(Loc);
2188
2189 OS << "\t.seh_startchained";
2190 EmitEOL();
2191}
2192
2193void MCAsmStreamer::emitWinCFIEndChained(SMLoc Loc) {
2194 MCStreamer::emitWinCFIEndChained(Loc);
2195
2196 OS << "\t.seh_endchained";
2197 EmitEOL();
2198}
2199
2200void MCAsmStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind,
2201 bool Except, SMLoc Loc) {
2202 MCStreamer::emitWinEHHandler(Sym, Unwind, Except, Loc);
2203
2204 OS << "\t.seh_handler ";
2205 Sym->print(OS, MAI);
2206 char Marker = '@';
2207 const Triple &T = getContext().getTargetTriple();
2208 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
2209 Marker = '%';
2210 if (Unwind)
2211 OS << ", " << Marker << "unwind";
2212 if (Except)
2213 OS << ", " << Marker << "except";
2214 EmitEOL();
2215}
2216
2217void MCAsmStreamer::emitWinEHHandlerData(SMLoc Loc) {
2218 MCStreamer::emitWinEHHandlerData(Loc);
2219
2220 // Switch sections. Don't call switchSection directly, because that will
2221 // cause the section switch to be visible in the emitted assembly.
2222 // We only do this so the section switch that terminates the handler
2223 // data block is visible.
2224 WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo();
2225
2226 // Do nothing if no frame is open. MCStreamer should've already reported an
2227 // error.
2228 if (!CurFrame)
2229 return;
2230
2231 MCSection *TextSec = &CurFrame->Function->getSection();
2232 MCSection *XData = getAssociatedXDataSection(TextSec);
2233 switchSectionNoPrint(Section: XData);
2234
2235 OS << "\t.seh_handlerdata";
2236 EmitEOL();
2237}
2238
2239void MCAsmStreamer::emitWinCFIPushReg(MCRegister Register, SMLoc Loc) {
2240 MCStreamer::emitWinCFIPushReg(Register, Loc);
2241
2242 OS << "\t.seh_pushreg ";
2243 InstPrinter->printRegName(OS, Reg: Register);
2244 EmitEOL();
2245}
2246
2247void MCAsmStreamer::emitWinCFISetFrame(MCRegister Register, unsigned Offset,
2248 SMLoc Loc) {
2249 MCStreamer::emitWinCFISetFrame(Register, Offset, Loc);
2250
2251 OS << "\t.seh_setframe ";
2252 InstPrinter->printRegName(OS, Reg: Register);
2253 OS << ", " << Offset;
2254 EmitEOL();
2255}
2256
2257void MCAsmStreamer::emitWinCFIAllocStack(unsigned Size, SMLoc Loc) {
2258 MCStreamer::emitWinCFIAllocStack(Size, Loc);
2259
2260 OS << "\t.seh_stackalloc " << Size;
2261 EmitEOL();
2262}
2263
2264void MCAsmStreamer::emitWinCFISaveReg(MCRegister Register, unsigned Offset,
2265 SMLoc Loc) {
2266 MCStreamer::emitWinCFISaveReg(Register, Offset, Loc);
2267
2268 OS << "\t.seh_savereg ";
2269 InstPrinter->printRegName(OS, Reg: Register);
2270 OS << ", " << Offset;
2271 EmitEOL();
2272}
2273
2274void MCAsmStreamer::emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
2275 SMLoc Loc) {
2276 MCStreamer::emitWinCFISaveXMM(Register, Offset, Loc);
2277
2278 OS << "\t.seh_savexmm ";
2279 InstPrinter->printRegName(OS, Reg: Register);
2280 OS << ", " << Offset;
2281 EmitEOL();
2282}
2283
2284void MCAsmStreamer::emitWinCFIPushFrame(bool Code, SMLoc Loc) {
2285 MCStreamer::emitWinCFIPushFrame(Code, Loc);
2286
2287 OS << "\t.seh_pushframe";
2288 if (Code)
2289 OS << " @code";
2290 EmitEOL();
2291}
2292
2293void MCAsmStreamer::emitWinCFIEndProlog(SMLoc Loc) {
2294 MCStreamer::emitWinCFIEndProlog(Loc);
2295
2296 OS << "\t.seh_endprologue";
2297 EmitEOL();
2298}
2299
2300void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
2301 const MCSymbolRefExpr *To,
2302 uint64_t Count) {
2303 OS << "\t.cg_profile ";
2304 From->getSymbol().print(OS, MAI);
2305 OS << ", ";
2306 To->getSymbol().print(OS, MAI);
2307 OS << ", " << Count;
2308 EmitEOL();
2309}
2310
2311void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
2312 const MCSubtargetInfo &STI) {
2313 raw_ostream &OS = getCommentOS();
2314 SmallString<256> Code;
2315 SmallVector<MCFixup, 4> Fixups;
2316
2317 // If we have no code emitter, don't emit code.
2318 if (!getAssembler().getEmitterPtr())
2319 return;
2320
2321 getAssembler().getEmitter().encodeInstruction(Inst, CB&: Code, Fixups, STI);
2322
2323 // If we are showing fixups, create symbolic markers in the encoded
2324 // representation. We do this by making a per-bit map to the fixup item index,
2325 // then trying to display it as nicely as possible.
2326 SmallVector<uint8_t, 64> FixupMap;
2327 FixupMap.resize(N: Code.size() * 8);
2328 for (unsigned i = 0, e = Code.size() * 8; i != e; ++i)
2329 FixupMap[i] = 0;
2330
2331 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
2332 MCFixup &F = Fixups[i];
2333 const MCFixupKindInfo &Info =
2334 getAssembler().getBackend().getFixupKindInfo(Kind: F.getKind());
2335 for (unsigned j = 0; j != Info.TargetSize; ++j) {
2336 unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
2337 assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
2338 FixupMap[Index] = 1 + i;
2339 }
2340 }
2341
2342 // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
2343 // high order halfword of a 32-bit Thumb2 instruction is emitted first.
2344 OS << "encoding: [";
2345 for (unsigned i = 0, e = Code.size(); i != e; ++i) {
2346 if (i)
2347 OS << ',';
2348
2349 // See if all bits are the same map entry.
2350 uint8_t MapEntry = FixupMap[i * 8 + 0];
2351 for (unsigned j = 1; j != 8; ++j) {
2352 if (FixupMap[i * 8 + j] == MapEntry)
2353 continue;
2354
2355 MapEntry = uint8_t(~0U);
2356 break;
2357 }
2358
2359 if (MapEntry != uint8_t(~0U)) {
2360 if (MapEntry == 0) {
2361 OS << format(Fmt: "0x%02x", Vals: uint8_t(Code[i]));
2362 } else {
2363 if (Code[i]) {
2364 // FIXME: Some of the 8 bits require fix up.
2365 OS << format(Fmt: "0x%02x", Vals: uint8_t(Code[i])) << '\''
2366 << char('A' + MapEntry - 1) << '\'';
2367 } else
2368 OS << char('A' + MapEntry - 1);
2369 }
2370 } else {
2371 // Otherwise, write out in binary.
2372 OS << "0b";
2373 for (unsigned j = 8; j--;) {
2374 unsigned Bit = (Code[i] >> j) & 1;
2375
2376 unsigned FixupBit;
2377 if (MAI->isLittleEndian())
2378 FixupBit = i * 8 + j;
2379 else
2380 FixupBit = i * 8 + (7-j);
2381
2382 if (uint8_t MapEntry = FixupMap[FixupBit]) {
2383 assert(Bit == 0 && "Encoder wrote into fixed up bit!");
2384 OS << char('A' + MapEntry - 1);
2385 } else
2386 OS << Bit;
2387 }
2388 }
2389 }
2390 OS << "]\n";
2391
2392 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
2393 MCFixup &F = Fixups[i];
2394 const MCFixupKindInfo &Info =
2395 getAssembler().getBackend().getFixupKindInfo(Kind: F.getKind());
2396 OS << " fixup " << char('A' + i) << " - "
2397 << "offset: " << F.getOffset() << ", value: ";
2398 F.getValue()->print(OS, MAI);
2399 OS << ", kind: " << Info.Name << "\n";
2400 }
2401}
2402
2403void MCAsmStreamer::emitInstruction(const MCInst &Inst,
2404 const MCSubtargetInfo &STI) {
2405 assert(getCurrentSectionOnly() &&
2406 "Cannot emit contents before setting section!");
2407
2408 if (!MAI->usesDwarfFileAndLocDirectives())
2409 // Now that a machine instruction has been assembled into this section, make
2410 // a line entry for any .loc directive that has been seen.
2411 MCDwarfLineEntry::make(MCOS: this, Section: getCurrentSectionOnly());
2412
2413 // Show the encoding in a comment if we have a code emitter.
2414 AddEncodingComment(Inst, STI);
2415
2416 // Show the MCInst if enabled.
2417 if (ShowInst) {
2418 Inst.dump_pretty(OS&: getCommentOS(), Printer: InstPrinter.get(), Separator: "\n ");
2419 getCommentOS() << "\n";
2420 }
2421
2422 if(getTargetStreamer())
2423 getTargetStreamer()->prettyPrintAsm(InstPrinter&: *InstPrinter, Address: 0, Inst, STI, OS);
2424 else
2425 InstPrinter->printInst(MI: &Inst, Address: 0, Annot: "", STI, OS);
2426
2427 StringRef Comments = CommentToEmit;
2428 if (Comments.size() && Comments.back() != '\n')
2429 getCommentOS() << "\n";
2430
2431 EmitEOL();
2432}
2433
2434void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,
2435 uint64_t Type, uint64_t Attr,
2436 uint64_t Discriminator,
2437 const MCPseudoProbeInlineStack &InlineStack,
2438 MCSymbol *FnSym) {
2439 OS << "\t.pseudoprobe\t" << Guid << " " << Index << " " << Type << " " << Attr;
2440 if (Discriminator)
2441 OS << " " << Discriminator;
2442 // Emit inline stack like
2443 // @ GUIDmain:3 @ GUIDCaller:1 @ GUIDDirectCaller:11
2444 for (const auto &Site : InlineStack)
2445 OS << " @ " << std::get<0>(t: Site) << ":" << std::get<1>(t: Site);
2446
2447 OS << " " << FnSym->getName();
2448
2449 EmitEOL();
2450}
2451
2452void MCAsmStreamer::emitBundleAlignMode(Align Alignment) {
2453 OS << "\t.bundle_align_mode " << Log2(A: Alignment);
2454 EmitEOL();
2455}
2456
2457void MCAsmStreamer::emitBundleLock(bool AlignToEnd) {
2458 OS << "\t.bundle_lock";
2459 if (AlignToEnd)
2460 OS << " align_to_end";
2461 EmitEOL();
2462}
2463
2464void MCAsmStreamer::emitBundleUnlock() {
2465 OS << "\t.bundle_unlock";
2466 EmitEOL();
2467}
2468
2469std::optional<std::pair<bool, std::string>>
2470MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
2471 const MCExpr *Expr, SMLoc,
2472 const MCSubtargetInfo &STI) {
2473 OS << "\t.reloc ";
2474 Offset.print(OS, MAI);
2475 OS << ", " << Name;
2476 if (Expr) {
2477 OS << ", ";
2478 Expr->print(OS, MAI);
2479 }
2480 EmitEOL();
2481 return std::nullopt;
2482}
2483
2484void MCAsmStreamer::emitAddrsig() {
2485 OS << "\t.addrsig";
2486 EmitEOL();
2487}
2488
2489void MCAsmStreamer::emitAddrsigSym(const MCSymbol *Sym) {
2490 OS << "\t.addrsig_sym ";
2491 Sym->print(OS, MAI);
2492 EmitEOL();
2493}
2494
2495/// EmitRawText - If this file is backed by an assembly streamer, this dumps
2496/// the specified string in the output .s file. This capability is
2497/// indicated by the hasRawTextSupport() predicate.
2498void MCAsmStreamer::emitRawTextImpl(StringRef String) {
2499 String.consume_back(Suffix: "\n");
2500 OS << String;
2501 EmitEOL();
2502}
2503
2504void MCAsmStreamer::finishImpl() {
2505 // If we are generating dwarf for assembly source files dump out the sections.
2506 if (getContext().getGenDwarfForAssembly())
2507 MCGenDwarfInfo::Emit(MCOS: this);
2508
2509 // Now it is time to emit debug line sections if target doesn't support .loc
2510 // and .line directives.
2511 if (!MAI->usesDwarfFileAndLocDirectives()) {
2512 MCDwarfLineTable::emit(MCOS: this, Params: getAssembler().getDWARFLinetableParams());
2513 return;
2514 }
2515
2516 // Emit the label for the line table, if requested - since the rest of the
2517 // line table will be defined by .loc/.file directives, and not emitted
2518 // directly, the label is the only work required here.
2519 const auto &Tables = getContext().getMCDwarfLineTables();
2520 if (!Tables.empty()) {
2521 assert(Tables.size() == 1 && "asm output only supports one line table");
2522 if (auto *Label = Tables.begin()->second.getLabel()) {
2523 switchSection(Section: getContext().getObjectFileInfo()->getDwarfLineSection());
2524 emitLabel(Symbol: Label);
2525 }
2526 }
2527}
2528
2529void MCAsmStreamer::emitDwarfUnitLength(uint64_t Length, const Twine &Comment) {
2530 // If the assembler on some target fills in the DWARF unit length, we
2531 // don't want to emit the length in the compiler. For example, the AIX
2532 // assembler requires the assembly file with the unit length omitted from
2533 // the debug section headers. In such cases, any label we placed occurs
2534 // after the implied length field. We need to adjust the reference here
2535 // to account for the offset introduced by the inserted length field.
2536 if (!MAI->needsDwarfSectionSizeInHeader())
2537 return;
2538 MCStreamer::emitDwarfUnitLength(Length, Comment);
2539}
2540
2541MCSymbol *MCAsmStreamer::emitDwarfUnitLength(const Twine &Prefix,
2542 const Twine &Comment) {
2543 // If the assembler on some target fills in the DWARF unit length, we
2544 // don't want to emit the length in the compiler. For example, the AIX
2545 // assembler requires the assembly file with the unit length omitted from
2546 // the debug section headers. In such cases, any label we placed occurs
2547 // after the implied length field. We need to adjust the reference here
2548 // to account for the offset introduced by the inserted length field.
2549 if (!MAI->needsDwarfSectionSizeInHeader())
2550 return getContext().createTempSymbol(Name: Prefix + "_end");
2551 return MCStreamer::emitDwarfUnitLength(Prefix, Comment);
2552}
2553
2554void MCAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
2555 // If the assembler on some target fills in the DWARF unit length, we
2556 // don't want to emit the length in the compiler. For example, the AIX
2557 // assembler requires the assembly file with the unit length omitted from
2558 // the debug section headers. In such cases, any label we placed occurs
2559 // after the implied length field. We need to adjust the reference here
2560 // to account for the offset introduced by the inserted length field.
2561 MCContext &Ctx = getContext();
2562 if (!MAI->needsDwarfSectionSizeInHeader()) {
2563 MCSymbol *DebugLineSymTmp = Ctx.createTempSymbol(Name: "debug_line_");
2564 // Emit the symbol which does not contain the unit length field.
2565 emitLabel(Symbol: DebugLineSymTmp);
2566
2567 // Adjust the outer reference to account for the offset introduced by the
2568 // inserted length field.
2569 unsigned LengthFieldSize =
2570 dwarf::getUnitLengthFieldByteSize(Format: Ctx.getDwarfFormat());
2571 const MCExpr *EntrySize = MCConstantExpr::create(Value: LengthFieldSize, Ctx);
2572 const MCExpr *OuterSym = MCBinaryExpr::createSub(
2573 LHS: MCSymbolRefExpr::create(Symbol: DebugLineSymTmp, Ctx), RHS: EntrySize, Ctx);
2574
2575 emitAssignment(Symbol: StartSym, Value: OuterSym);
2576 return;
2577 }
2578 MCStreamer::emitDwarfLineStartLabel(StartSym);
2579}
2580
2581void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
2582 MCSymbol *LastLabel) {
2583 // If the targets write the raw debug line data for assembly output (We can
2584 // not switch to Section and add the end symbol there for assembly output)
2585 // we currently use the .text end label as any section end. This will not
2586 // impact the debugability as we will jump to the caller of the last function
2587 // in the section before we come into the .text end address.
2588 assert(!MAI->usesDwarfFileAndLocDirectives() &&
2589 ".loc should not be generated together with raw data!");
2590
2591 MCContext &Ctx = getContext();
2592
2593 // FIXME: use section end symbol as end of the Section. We need to consider
2594 // the explicit sections and -ffunction-sections when we try to generate or
2595 // find section end symbol for the Section.
2596 MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();
2597 assert(TextSection->hasEnded() && ".text section is not end!");
2598
2599 MCSymbol *SectionEnd = TextSection->getEndSymbol(Ctx);
2600 const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
2601 emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label: SectionEnd,
2602 PointerSize: AsmInfo->getCodePointerSize());
2603}
2604
2605// Generate DWARF line sections for assembly mode without .loc/.file
2606void MCAsmStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
2607 const MCSymbol *LastLabel,
2608 const MCSymbol *Label,
2609 unsigned PointerSize) {
2610 assert(!MAI->usesDwarfFileAndLocDirectives() &&
2611 ".loc/.file don't need raw data in debug line section!");
2612
2613 // Set to new address.
2614 AddComment(T: "Set address to " + Label->getName());
2615 emitIntValue(Value: dwarf::DW_LNS_extended_op, Size: 1);
2616 emitULEB128IntValue(Value: PointerSize + 1);
2617 emitIntValue(Value: dwarf::DW_LNE_set_address, Size: 1);
2618 emitSymbolValue(Sym: Label, Size: PointerSize);
2619
2620 if (!LastLabel) {
2621 // Emit the sequence for the LineDelta (from 1) and a zero address delta.
2622 AddComment(T: "Start sequence");
2623 MCDwarfLineAddr::Emit(MCOS: this, Params: MCDwarfLineTableParams(), LineDelta, AddrDelta: 0);
2624 return;
2625 }
2626
2627 // INT64_MAX is a signal of the end of the section. Emit DW_LNE_end_sequence
2628 // for the end of the section.
2629 if (LineDelta == INT64_MAX) {
2630 AddComment(T: "End sequence");
2631 emitIntValue(Value: dwarf::DW_LNS_extended_op, Size: 1);
2632 emitULEB128IntValue(Value: 1);
2633 emitIntValue(Value: dwarf::DW_LNE_end_sequence, Size: 1);
2634 return;
2635 }
2636
2637 // Advance line.
2638 AddComment(T: "Advance line " + Twine(LineDelta));
2639 emitIntValue(Value: dwarf::DW_LNS_advance_line, Size: 1);
2640 emitSLEB128IntValue(Value: LineDelta);
2641 emitIntValue(Value: dwarf::DW_LNS_copy, Size: 1);
2642}
2643
2644void MCAsmStreamer::doFinalizationAtSectionEnd(MCSection *Section) {
2645 // Emit section end. This is used to tell the debug line section where the end
2646 // is for a text section if we don't use .loc to represent the debug line.
2647 if (MAI->usesDwarfFileAndLocDirectives())
2648 return;
2649
2650 switchSectionNoPrint(Section);
2651
2652 MCSymbol *Sym = getCurrentSectionOnly()->getEndSymbol(Ctx&: getContext());
2653
2654 if (!Sym->isInSection())
2655 emitLabel(Symbol: Sym);
2656}
2657
2658MCStreamer *llvm::createAsmStreamer(MCContext &Context,
2659 std::unique_ptr<formatted_raw_ostream> OS,
2660 MCInstPrinter *IP,
2661 std::unique_ptr<MCCodeEmitter> &&CE,
2662 std::unique_ptr<MCAsmBackend> &&MAB) {
2663 return new MCAsmStreamer(Context, std::move(OS), IP, std::move(CE),
2664 std::move(MAB));
2665}
2666