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