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