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