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