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