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