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