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