/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/MC/MCAsmStreamer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "llvm/ADT/Optional.h" |
10 | | #include "llvm/ADT/STLExtras.h" |
11 | | #include "llvm/ADT/SmallString.h" |
12 | | #include "llvm/ADT/StringExtras.h" |
13 | | #include "llvm/ADT/Twine.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/MCFixupKindInfo.h" |
22 | | #include "llvm/MC/MCInst.h" |
23 | | #include "llvm/MC/MCInstPrinter.h" |
24 | | #include "llvm/MC/MCObjectFileInfo.h" |
25 | | #include "llvm/MC/MCObjectWriter.h" |
26 | | #include "llvm/MC/MCRegisterInfo.h" |
27 | | #include "llvm/MC/MCSectionMachO.h" |
28 | | #include "llvm/MC/MCStreamer.h" |
29 | | #include "llvm/Support/ErrorHandling.h" |
30 | | #include "llvm/Support/Format.h" |
31 | | #include "llvm/Support/FormattedStream.h" |
32 | | #include "llvm/Support/LEB128.h" |
33 | | #include "llvm/Support/MathExtras.h" |
34 | | #include "llvm/Support/Path.h" |
35 | | #include "llvm/Support/TargetRegistry.h" |
36 | | #include <cctype> |
37 | | |
38 | | using namespace llvm; |
39 | | |
40 | | namespace { |
41 | | |
42 | | class MCAsmStreamer final : public MCStreamer { |
43 | | std::unique_ptr<formatted_raw_ostream> OSOwner; |
44 | | formatted_raw_ostream &OS; |
45 | | const MCAsmInfo *MAI; |
46 | | std::unique_ptr<MCInstPrinter> InstPrinter; |
47 | | std::unique_ptr<MCAssembler> Assembler; |
48 | | |
49 | | SmallString<128> ExplicitCommentToEmit; |
50 | | SmallString<128> CommentToEmit; |
51 | | raw_svector_ostream CommentStream; |
52 | | raw_null_ostream NullStream; |
53 | | |
54 | | unsigned IsVerboseAsm : 1; |
55 | | unsigned ShowInst : 1; |
56 | | unsigned UseDwarfDirectory : 1; |
57 | | |
58 | | void EmitRegisterName(int64_t Register); |
59 | | void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override; |
60 | | void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override; |
61 | | |
62 | | public: |
63 | | MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> os, |
64 | | bool isVerboseAsm, bool useDwarfDirectory, |
65 | | MCInstPrinter *printer, std::unique_ptr<MCCodeEmitter> emitter, |
66 | | std::unique_ptr<MCAsmBackend> asmbackend, bool showInst) |
67 | | : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner), |
68 | | MAI(Context.getAsmInfo()), InstPrinter(printer), |
69 | | Assembler(llvm::make_unique<MCAssembler>( |
70 | | Context, std::move(asmbackend), std::move(emitter), |
71 | | (asmbackend) ? asmbackend->createObjectWriter(NullStream) |
72 | | : nullptr)), |
73 | | CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), |
74 | 26.7k | ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) { |
75 | 26.7k | assert(InstPrinter); |
76 | 26.7k | if (IsVerboseAsm) |
77 | 26.2k | InstPrinter->setCommentStream(CommentStream); |
78 | 26.7k | } |
79 | | |
80 | 3.36M | MCAssembler &getAssembler() { return *Assembler; } |
81 | 520k | MCAssembler *getAssemblerPtr() override { return nullptr; } |
82 | | |
83 | 7.01M | inline void EmitEOL() { |
84 | 7.01M | // Dump Explicit Comments here. |
85 | 7.01M | emitExplicitComments(); |
86 | 7.01M | // If we don't have any comments, just emit a \n. |
87 | 7.01M | if (!IsVerboseAsm) { |
88 | 132k | OS << '\n'; |
89 | 132k | return; |
90 | 132k | } |
91 | 6.88M | EmitCommentsAndEOL(); |
92 | 6.88M | } |
93 | | |
94 | | void EmitSyntaxDirective() override; |
95 | | |
96 | | void EmitCommentsAndEOL(); |
97 | | |
98 | | /// Return true if this streamer supports verbose assembly at all. |
99 | 80.1k | bool isVerboseAsm() const override { return IsVerboseAsm; } |
100 | | |
101 | | /// Do we support EmitRawText? |
102 | 5.10k | bool hasRawTextSupport() const override { return true; } |
103 | | |
104 | | /// Add a comment that can be emitted to the generated .s file to make the |
105 | | /// output of the compiler more readable. This only affects the MCAsmStreamer |
106 | | /// and only when verbose assembly output is enabled. |
107 | | void AddComment(const Twine &T, bool EOL = true) override; |
108 | | |
109 | | /// Add a comment showing the encoding of an instruction. |
110 | | void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &); |
111 | | |
112 | | /// Return a raw_ostream that comments can be written to. |
113 | | /// Unlike AddComment, you are required to terminate comments with \n if you |
114 | | /// use this method. |
115 | 6.11M | raw_ostream &GetCommentOS() override { |
116 | 6.11M | if (!IsVerboseAsm) |
117 | 72.1k | return nulls(); // Discard comments unless in verbose asm mode. |
118 | 6.04M | return CommentStream; |
119 | 6.04M | } |
120 | | |
121 | | void emitRawComment(const Twine &T, bool TabPrefix = true) override; |
122 | | |
123 | | void addExplicitComment(const Twine &T) override; |
124 | | void emitExplicitComments() override; |
125 | | |
126 | | /// Emit a blank line to a .s file to pretty it up. |
127 | 1.06M | void AddBlankLine() override { |
128 | 1.06M | EmitEOL(); |
129 | 1.06M | } |
130 | | |
131 | | /// @name MCStreamer Interface |
132 | | /// @{ |
133 | | |
134 | | void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; |
135 | | |
136 | | void emitELFSymverDirective(StringRef AliasName, |
137 | | const MCSymbol *Aliasee) override; |
138 | | |
139 | | void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override; |
140 | | void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; |
141 | | |
142 | | void EmitAssemblerFlag(MCAssemblerFlag Flag) override; |
143 | | void EmitLinkerOptions(ArrayRef<std::string> Options) override; |
144 | | void EmitDataRegion(MCDataRegionType Kind) override; |
145 | | void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, |
146 | | unsigned Update, VersionTuple SDKVersion) override; |
147 | | void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, |
148 | | unsigned Update, VersionTuple SDKVersion) override; |
149 | | void EmitThumbFunc(MCSymbol *Func) override; |
150 | | |
151 | | void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; |
152 | | void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; |
153 | | bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; |
154 | | |
155 | | void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; |
156 | | void BeginCOFFSymbolDef(const MCSymbol *Symbol) override; |
157 | | void EmitCOFFSymbolStorageClass(int StorageClass) override; |
158 | | void EmitCOFFSymbolType(int Type) override; |
159 | | void EndCOFFSymbolDef() override; |
160 | | void EmitCOFFSafeSEH(MCSymbol const *Symbol) override; |
161 | | void EmitCOFFSymbolIndex(MCSymbol const *Symbol) override; |
162 | | void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; |
163 | | void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; |
164 | | void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; |
165 | | void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; |
166 | | void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
167 | | unsigned ByteAlignment) override; |
168 | | |
169 | | /// Emit a local common (.lcomm) symbol. |
170 | | /// |
171 | | /// @param Symbol - The common symbol to emit. |
172 | | /// @param Size - The size of the common symbol. |
173 | | /// @param ByteAlignment - The alignment of the common symbol in bytes. |
174 | | void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
175 | | unsigned ByteAlignment) override; |
176 | | |
177 | | void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, |
178 | | uint64_t Size = 0, unsigned ByteAlignment = 0, |
179 | | SMLoc Loc = SMLoc()) override; |
180 | | |
181 | | void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, |
182 | | unsigned ByteAlignment = 0) override; |
183 | | |
184 | | void EmitBinaryData(StringRef Data) override; |
185 | | |
186 | | void EmitBytes(StringRef Data) override; |
187 | | |
188 | | void EmitValueImpl(const MCExpr *Value, unsigned Size, |
189 | | SMLoc Loc = SMLoc()) override; |
190 | | void EmitIntValue(uint64_t Value, unsigned Size) override; |
191 | | void EmitIntValueInHex(uint64_t Value, unsigned Size) override; |
192 | | |
193 | | void EmitULEB128Value(const MCExpr *Value) override; |
194 | | |
195 | | void EmitSLEB128Value(const MCExpr *Value) override; |
196 | | |
197 | | void EmitDTPRel32Value(const MCExpr *Value) override; |
198 | | void EmitDTPRel64Value(const MCExpr *Value) override; |
199 | | void EmitTPRel32Value(const MCExpr *Value) override; |
200 | | void EmitTPRel64Value(const MCExpr *Value) override; |
201 | | |
202 | | void EmitGPRel64Value(const MCExpr *Value) override; |
203 | | |
204 | | void EmitGPRel32Value(const MCExpr *Value) override; |
205 | | |
206 | | void emitFill(const MCExpr &NumBytes, uint64_t FillValue, |
207 | | SMLoc Loc = SMLoc()) override; |
208 | | |
209 | | void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, |
210 | | SMLoc Loc = SMLoc()) override; |
211 | | |
212 | | void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, |
213 | | unsigned ValueSize = 1, |
214 | | unsigned MaxBytesToEmit = 0) override; |
215 | | |
216 | | void EmitCodeAlignment(unsigned ByteAlignment, |
217 | | unsigned MaxBytesToEmit = 0) override; |
218 | | |
219 | | void emitValueToOffset(const MCExpr *Offset, |
220 | | unsigned char Value, |
221 | | SMLoc Loc) override; |
222 | | |
223 | | void EmitFileDirective(StringRef Filename) override; |
224 | | Expected<unsigned> tryEmitDwarfFileDirective(unsigned FileNo, |
225 | | StringRef Directory, |
226 | | StringRef Filename, |
227 | | Optional<MD5::MD5Result> Checksum = None, |
228 | | Optional<StringRef> Source = None, |
229 | | unsigned CUID = 0) override; |
230 | | void emitDwarfFile0Directive(StringRef Directory, StringRef Filename, |
231 | | Optional<MD5::MD5Result> Checksum, |
232 | | Optional<StringRef> Source, |
233 | | unsigned CUID = 0) override; |
234 | | void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, |
235 | | unsigned Column, unsigned Flags, |
236 | | unsigned Isa, unsigned Discriminator, |
237 | | StringRef FileName) override; |
238 | | MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override; |
239 | | |
240 | | bool EmitCVFileDirective(unsigned FileNo, StringRef Filename, |
241 | | ArrayRef<uint8_t> Checksum, |
242 | | unsigned ChecksumKind) override; |
243 | | bool EmitCVFuncIdDirective(unsigned FuncId) override; |
244 | | bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, |
245 | | unsigned IAFile, unsigned IALine, |
246 | | unsigned IACol, SMLoc Loc) override; |
247 | | void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, |
248 | | unsigned Column, bool PrologueEnd, bool IsStmt, |
249 | | StringRef FileName, SMLoc Loc) override; |
250 | | void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart, |
251 | | const MCSymbol *FnEnd) override; |
252 | | void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, |
253 | | unsigned SourceFileId, |
254 | | unsigned SourceLineNum, |
255 | | const MCSymbol *FnStartSym, |
256 | | const MCSymbol *FnEndSym) override; |
257 | | void EmitCVDefRangeDirective( |
258 | | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
259 | | StringRef FixedSizePortion) override; |
260 | | void EmitCVStringTableDirective() override; |
261 | | void EmitCVFileChecksumsDirective() override; |
262 | | void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override; |
263 | | void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override; |
264 | | |
265 | | void EmitIdent(StringRef IdentString) override; |
266 | | void EmitCFIBKeyFrame() override; |
267 | | void EmitCFISections(bool EH, bool Debug) override; |
268 | | void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; |
269 | | void EmitCFIDefCfaOffset(int64_t Offset) override; |
270 | | void EmitCFIDefCfaRegister(int64_t Register) override; |
271 | | void EmitCFIOffset(int64_t Register, int64_t Offset) override; |
272 | | void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override; |
273 | | void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) override; |
274 | | void EmitCFIRememberState() override; |
275 | | void EmitCFIRestoreState() override; |
276 | | void EmitCFIRestore(int64_t Register) override; |
277 | | void EmitCFISameValue(int64_t Register) override; |
278 | | void EmitCFIRelOffset(int64_t Register, int64_t Offset) override; |
279 | | void EmitCFIAdjustCfaOffset(int64_t Adjustment) override; |
280 | | void EmitCFIEscape(StringRef Values) override; |
281 | | void EmitCFIGnuArgsSize(int64_t Size) override; |
282 | | void EmitCFISignalFrame() override; |
283 | | void EmitCFIUndefined(int64_t Register) override; |
284 | | void EmitCFIRegister(int64_t Register1, int64_t Register2) override; |
285 | | void EmitCFIWindowSave() override; |
286 | | void EmitCFINegateRAState() override; |
287 | | void EmitCFIReturnColumn(int64_t Register) override; |
288 | | |
289 | | void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override; |
290 | | void EmitWinCFIEndProc(SMLoc Loc) override; |
291 | | void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override; |
292 | | void EmitWinCFIStartChained(SMLoc Loc) override; |
293 | | void EmitWinCFIEndChained(SMLoc Loc) override; |
294 | | void EmitWinCFIPushReg(unsigned Register, SMLoc Loc) override; |
295 | | void EmitWinCFISetFrame(unsigned Register, unsigned Offset, |
296 | | SMLoc Loc) override; |
297 | | void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override; |
298 | | void EmitWinCFISaveReg(unsigned Register, unsigned Offset, |
299 | | SMLoc Loc) override; |
300 | | void EmitWinCFISaveXMM(unsigned Register, unsigned Offset, |
301 | | SMLoc Loc) override; |
302 | | void EmitWinCFIPushFrame(bool Code, SMLoc Loc) override; |
303 | | void EmitWinCFIEndProlog(SMLoc Loc) override; |
304 | | |
305 | | void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, |
306 | | SMLoc Loc) override; |
307 | | void EmitWinEHHandlerData(SMLoc Loc) override; |
308 | | |
309 | | void emitCGProfileEntry(const MCSymbolRefExpr *From, |
310 | | const MCSymbolRefExpr *To, uint64_t Count) override; |
311 | | |
312 | | void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; |
313 | | |
314 | | void EmitBundleAlignMode(unsigned AlignPow2) override; |
315 | | void EmitBundleLock(bool AlignToEnd) override; |
316 | | void EmitBundleUnlock() override; |
317 | | |
318 | | bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, |
319 | | const MCExpr *Expr, SMLoc Loc, |
320 | | const MCSubtargetInfo &STI) override; |
321 | | |
322 | | void EmitAddrsig() override; |
323 | | void EmitAddrsigSym(const MCSymbol *Sym) override; |
324 | | |
325 | | /// If this file is backed by an assembly streamer, this dumps the specified |
326 | | /// string in the output .s file. This capability is indicated by the |
327 | | /// hasRawTextSupport() predicate. |
328 | | void EmitRawTextImpl(StringRef String) override; |
329 | | |
330 | | void FinishImpl() override; |
331 | | }; |
332 | | |
333 | | } // end anonymous namespace. |
334 | | |
335 | 179k | void MCAsmStreamer::AddComment(const Twine &T, bool EOL) { |
336 | 179k | if (!IsVerboseAsm) return1.60k ; |
337 | 177k | |
338 | 177k | T.toVector(CommentToEmit); |
339 | 177k | |
340 | 177k | if (EOL) |
341 | 171k | CommentToEmit.push_back('\n'); // Place comment in a new line. |
342 | 177k | } |
343 | | |
344 | 6.88M | void MCAsmStreamer::EmitCommentsAndEOL() { |
345 | 6.88M | if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 04.86M ) { |
346 | 4.86M | OS << '\n'; |
347 | 4.86M | return; |
348 | 4.86M | } |
349 | 2.01M | |
350 | 2.01M | StringRef Comments = CommentToEmit; |
351 | 2.01M | |
352 | 2.01M | assert(Comments.back() == '\n' && |
353 | 2.01M | "Comment array not newline terminated"); |
354 | 2.08M | do { |
355 | 2.08M | // Emit a line of comments. |
356 | 2.08M | OS.PadToColumn(MAI->getCommentColumn()); |
357 | 2.08M | size_t Position = Comments.find('\n'); |
358 | 2.08M | OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n'; |
359 | 2.08M | |
360 | 2.08M | Comments = Comments.substr(Position+1); |
361 | 2.08M | } while (!Comments.empty()); |
362 | 2.01M | |
363 | 2.01M | CommentToEmit.clear(); |
364 | 2.01M | } |
365 | | |
366 | 113k | static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { |
367 | 113k | assert(Bytes > 0 && Bytes <= 8 && "Invalid size!"); |
368 | 113k | return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); |
369 | 113k | } |
370 | | |
371 | 729k | void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) { |
372 | 729k | if (TabPrefix) |
373 | 27.3k | OS << '\t'; |
374 | 729k | OS << MAI->getCommentString() << T; |
375 | 729k | EmitEOL(); |
376 | 729k | } |
377 | | |
378 | 320 | void MCAsmStreamer::addExplicitComment(const Twine &T) { |
379 | 320 | StringRef c = T.getSingleStringRef(); |
380 | 320 | if (c.equals(StringRef(MAI->getSeparatorString()))) |
381 | 64 | return; |
382 | 256 | if (c.startswith(StringRef("//"))) { |
383 | 51 | ExplicitCommentToEmit.append("\t"); |
384 | 51 | ExplicitCommentToEmit.append(MAI->getCommentString()); |
385 | 51 | // drop // |
386 | 51 | ExplicitCommentToEmit.append(c.slice(2, c.size()).str()); |
387 | 205 | } else if (c.startswith(StringRef("/*"))) { |
388 | 13 | size_t p = 2, len = c.size() - 2; |
389 | 13 | // emit each line in comment as separate newline. |
390 | 14 | do { |
391 | 14 | size_t newp = std::min(len, c.find_first_of("\r\n", p)); |
392 | 14 | ExplicitCommentToEmit.append("\t"); |
393 | 14 | ExplicitCommentToEmit.append(MAI->getCommentString()); |
394 | 14 | ExplicitCommentToEmit.append(c.slice(p, newp).str()); |
395 | 14 | // If we have another line in this comment add line |
396 | 14 | if (newp < len) |
397 | 1 | ExplicitCommentToEmit.append("\n"); |
398 | 14 | p = newp + 1; |
399 | 14 | } while (p < len); |
400 | 192 | } else if (c.startswith(StringRef(MAI->getCommentString()))) { |
401 | 170 | ExplicitCommentToEmit.append("\t"); |
402 | 170 | ExplicitCommentToEmit.append(c.str()); |
403 | 170 | } else if (22 c.front() == '#'22 ) { |
404 | 22 | |
405 | 22 | ExplicitCommentToEmit.append("\t"); |
406 | 22 | ExplicitCommentToEmit.append(MAI->getCommentString()); |
407 | 22 | ExplicitCommentToEmit.append(c.slice(1, c.size()).str()); |
408 | 22 | } else |
409 | 22 | assert(false && "Unexpected Assembly Comment"); |
410 | 256 | // full line comments immediately output |
411 | 256 | if (c.back() == '\n') |
412 | 228 | emitExplicitComments(); |
413 | 256 | } |
414 | | |
415 | 7.01M | void MCAsmStreamer::emitExplicitComments() { |
416 | 7.01M | StringRef Comments = ExplicitCommentToEmit; |
417 | 7.01M | if (!Comments.empty()) |
418 | 252 | OS << Comments; |
419 | 7.01M | ExplicitCommentToEmit.clear(); |
420 | 7.01M | } |
421 | | |
422 | | void MCAsmStreamer::ChangeSection(MCSection *Section, |
423 | 205k | const MCExpr *Subsection) { |
424 | 205k | assert(Section && "Cannot switch to a null section!"); |
425 | 205k | if (MCTargetStreamer *TS = getTargetStreamer()) { |
426 | 194k | TS->changeSection(getCurrentSectionOnly(), Section, Subsection, OS); |
427 | 194k | } else { |
428 | 11.6k | Section->PrintSwitchToSection( |
429 | 11.6k | *MAI, getContext().getObjectFileInfo()->getTargetTriple(), OS, |
430 | 11.6k | Subsection); |
431 | 11.6k | } |
432 | 205k | } |
433 | | |
434 | | void MCAsmStreamer::emitELFSymverDirective(StringRef AliasName, |
435 | 6 | const MCSymbol *Aliasee) { |
436 | 6 | OS << ".symver "; |
437 | 6 | Aliasee->print(OS, MAI); |
438 | 6 | OS << ", " << AliasName; |
439 | 6 | EmitEOL(); |
440 | 6 | } |
441 | | |
442 | 538k | void MCAsmStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { |
443 | 538k | MCStreamer::EmitLabel(Symbol, Loc); |
444 | 538k | |
445 | 538k | Symbol->print(OS, MAI); |
446 | 538k | OS << MAI->getLabelSuffix(); |
447 | 538k | |
448 | 538k | EmitEOL(); |
449 | 538k | } |
450 | | |
451 | 238 | void MCAsmStreamer::EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) { |
452 | 238 | StringRef str = MCLOHIdToName(Kind); |
453 | 238 | |
454 | | #ifndef NDEBUG |
455 | | int NbArgs = MCLOHIdToNbArgs(Kind); |
456 | | assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!"); |
457 | | assert(str != "" && "Invalid LOH name"); |
458 | | #endif |
459 | | |
460 | 238 | OS << "\t" << MCLOHDirectiveName() << " " << str << "\t"; |
461 | 238 | bool IsFirst = true; |
462 | 543 | for (const MCSymbol *Arg : Args) { |
463 | 543 | if (!IsFirst) |
464 | 305 | OS << ", "; |
465 | 543 | IsFirst = false; |
466 | 543 | Arg->print(OS, MAI); |
467 | 543 | } |
468 | 238 | EmitEOL(); |
469 | 238 | } |
470 | | |
471 | 22.2k | void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { |
472 | 22.2k | switch (Flag) { |
473 | 22.2k | case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break2.89k ; |
474 | 22.2k | case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break2.51k ; |
475 | 22.2k | case MCAF_Code16: OS << '\t'<< MAI->getCode16Directive();break7.86k ; |
476 | 22.2k | case MCAF_Code32: OS << '\t'<< MAI->getCode32Directive();break8.93k ; |
477 | 22.2k | case MCAF_Code64: OS << '\t'<< MAI->getCode64Directive();break2 ; |
478 | 22.2k | } |
479 | 22.2k | EmitEOL(); |
480 | 22.2k | } |
481 | | |
482 | 5 | void MCAsmStreamer::EmitLinkerOptions(ArrayRef<std::string> Options) { |
483 | 5 | assert(!Options.empty() && "At least one option is required!"); |
484 | 5 | OS << "\t.linker_option \"" << Options[0] << '"'; |
485 | 5 | for (ArrayRef<std::string>::iterator it = Options.begin() + 1, |
486 | 7 | ie = Options.end(); it != ie; ++it2 ) { |
487 | 2 | OS << ", " << '"' << *it << '"'; |
488 | 2 | } |
489 | 5 | EmitEOL(); |
490 | 5 | } |
491 | | |
492 | 3.69k | void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) { |
493 | 3.69k | if (!MAI->doesSupportDataRegionDirectives()) |
494 | 2.81k | return; |
495 | 884 | switch (Kind) { |
496 | 884 | case MCDR_DataRegion: OS << "\t.data_region"; break392 ; |
497 | 884 | case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break15 ; |
498 | 884 | case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break0 ; |
499 | 884 | case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break35 ; |
500 | 884 | case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break442 ; |
501 | 884 | } |
502 | 884 | EmitEOL(); |
503 | 884 | } |
504 | | |
505 | 1.07k | static const char *getVersionMinDirective(MCVersionMinType Type) { |
506 | 1.07k | switch (Type) { |
507 | 1.07k | case MCVM_WatchOSVersionMin: return ".watchos_version_min"26 ; |
508 | 1.07k | case MCVM_TvOSVersionMin: return ".tvos_version_min"18 ; |
509 | 1.07k | case MCVM_IOSVersionMin: return ".ios_version_min"185 ; |
510 | 1.07k | case MCVM_OSXVersionMin: return ".macosx_version_min"848 ; |
511 | 0 | } |
512 | 0 | llvm_unreachable("Invalid MC version min type"); |
513 | 0 | } |
514 | | |
515 | | static void EmitSDKVersionSuffix(raw_ostream &OS, |
516 | 1.09k | const VersionTuple &SDKVersion) { |
517 | 1.09k | if (SDKVersion.empty()) |
518 | 1.08k | return; |
519 | 11 | OS << '\t' << "sdk_version " << SDKVersion.getMajor(); |
520 | 11 | if (auto Minor = SDKVersion.getMinor()) { |
521 | 11 | OS << ", " << *Minor; |
522 | 11 | if (auto Subminor = SDKVersion.getSubminor()) { |
523 | 3 | OS << ", " << *Subminor; |
524 | 3 | } |
525 | 11 | } |
526 | 11 | } |
527 | | |
528 | | void MCAsmStreamer::EmitVersionMin(MCVersionMinType Type, unsigned Major, |
529 | | unsigned Minor, unsigned Update, |
530 | 1.07k | VersionTuple SDKVersion) { |
531 | 1.07k | OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor; |
532 | 1.07k | if (Update) |
533 | 43 | OS << ", " << Update; |
534 | 1.07k | EmitSDKVersionSuffix(OS, SDKVersion); |
535 | 1.07k | EmitEOL(); |
536 | 1.07k | } |
537 | | |
538 | 14 | static const char *getPlatformName(MachO::PlatformType Type) { |
539 | 14 | switch (Type) { |
540 | 14 | case MachO::PLATFORM_MACOS: return "macos"5 ; |
541 | 14 | case MachO::PLATFORM_IOS: return "ios"2 ; |
542 | 14 | case MachO::PLATFORM_TVOS: return "tvos"3 ; |
543 | 14 | case MachO::PLATFORM_WATCHOS: return "watchos"2 ; |
544 | 14 | case MachO::PLATFORM_BRIDGEOS: return "bridgeos"0 ; |
545 | 14 | case MachO::PLATFORM_MACCATALYST: return "macCatalyst"2 ; |
546 | 14 | case MachO::PLATFORM_IOSSIMULATOR: return "iossimulator"0 ; |
547 | 14 | case MachO::PLATFORM_TVOSSIMULATOR: return "tvossimulator"0 ; |
548 | 14 | case MachO::PLATFORM_WATCHOSSIMULATOR: return "watchossimulator"0 ; |
549 | 0 | } |
550 | 0 | llvm_unreachable("Invalid Mach-O platform type"); |
551 | 0 | } |
552 | | |
553 | | void MCAsmStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, |
554 | | unsigned Minor, unsigned Update, |
555 | 14 | VersionTuple SDKVersion) { |
556 | 14 | const char *PlatformName = getPlatformName((MachO::PlatformType)Platform); |
557 | 14 | OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor; |
558 | 14 | if (Update) |
559 | 4 | OS << ", " << Update; |
560 | 14 | EmitSDKVersionSuffix(OS, SDKVersion); |
561 | 14 | EmitEOL(); |
562 | 14 | } |
563 | | |
564 | 7.67k | void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { |
565 | 7.67k | // This needs to emit to a temporary string to get properly quoted |
566 | 7.67k | // MCSymbols when they have spaces in them. |
567 | 7.67k | OS << "\t.thumb_func"; |
568 | 7.67k | // Only Mach-O hasSubsectionsViaSymbols() |
569 | 7.67k | if (MAI->hasSubsectionsViaSymbols()) { |
570 | 1.33k | OS << '\t'; |
571 | 1.33k | Func->print(OS, MAI); |
572 | 1.33k | } |
573 | 7.67k | EmitEOL(); |
574 | 7.67k | } |
575 | | |
576 | 2.93k | void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { |
577 | 2.93k | // Do not emit a .set on inlined target assignments. |
578 | 2.93k | bool EmitSet = true; |
579 | 2.93k | if (auto *E = dyn_cast<MCTargetExpr>(Value)) |
580 | 12 | if (E->inlineAssignedExpr()) |
581 | 12 | EmitSet = false; |
582 | 2.93k | if (EmitSet) { |
583 | 2.92k | OS << ".set "; |
584 | 2.92k | Symbol->print(OS, MAI); |
585 | 2.92k | OS << ", "; |
586 | 2.92k | Value->print(OS, MAI); |
587 | 2.92k | |
588 | 2.92k | EmitEOL(); |
589 | 2.92k | } |
590 | 2.93k | |
591 | 2.93k | MCStreamer::EmitAssignment(Symbol, Value); |
592 | 2.93k | } |
593 | | |
594 | 0 | void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { |
595 | 0 | OS << ".weakref "; |
596 | 0 | Alias->print(OS, MAI); |
597 | 0 | OS << ", "; |
598 | 0 | Symbol->print(OS, MAI); |
599 | 0 | EmitEOL(); |
600 | 0 | } |
601 | | |
602 | | bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, |
603 | 441k | MCSymbolAttr Attribute) { |
604 | 441k | switch (Attribute) { |
605 | 441k | case MCSA_Invalid: 0 llvm_unreachable0 ("Invalid symbol attribute"); |
606 | 441k | case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function |
607 | 208k | case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC |
608 | 208k | case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object |
609 | 208k | case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object |
610 | 208k | case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common |
611 | 208k | case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype |
612 | 208k | case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object |
613 | 208k | if (!MAI->hasDotTypeDotSizeDirective()) |
614 | 83 | return false; // Symbol attribute not supported |
615 | 208k | OS << "\t.type\t"; |
616 | 208k | Symbol->print(OS, MAI); |
617 | 208k | OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@'193k : '%'14.7k ); |
618 | 208k | switch (Attribute) { |
619 | 208k | default: return false0 ; |
620 | 208k | case MCSA_ELF_TypeFunction: OS << "function"; break197k ; |
621 | 208k | case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break7 ; |
622 | 208k | case MCSA_ELF_TypeObject: OS << "object"; break11.3k ; |
623 | 208k | case MCSA_ELF_TypeTLS: OS << "tls_object"; break1 ; |
624 | 208k | case MCSA_ELF_TypeCommon: OS << "common"; break1 ; |
625 | 208k | case MCSA_ELF_TypeNoType: OS << "notype"; break1 ; |
626 | 208k | case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break3 ; |
627 | 208k | } |
628 | 208k | EmitEOL(); |
629 | 208k | return true; |
630 | 230k | case MCSA_Global: // .globl/.global |
631 | 230k | OS << MAI->getGlobalDirective(); |
632 | 230k | break; |
633 | 208k | case MCSA_Hidden: OS << "\t.hidden\t"; break877 ; |
634 | 208k | case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break587 ; |
635 | 208k | case MCSA_Internal: OS << "\t.internal\t"; break0 ; |
636 | 208k | case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break9 ; |
637 | 208k | case MCSA_Local: OS << "\t.local\t"; break260 ; |
638 | 208k | case MCSA_NoDeadStrip: |
639 | 145 | if (!MAI->hasNoDeadStrip()) |
640 | 68 | return false; |
641 | 77 | OS << "\t.no_dead_strip\t"; |
642 | 77 | break; |
643 | 77 | case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break4 ; |
644 | 77 | case MCSA_AltEntry: OS << "\t.alt_entry\t"; break8 ; |
645 | 88 | case MCSA_PrivateExtern: |
646 | 88 | OS << "\t.private_extern\t"; |
647 | 88 | break; |
648 | 77 | case MCSA_Protected: OS << "\t.protected\t"; break50 ; |
649 | 77 | case MCSA_Reference: OS << "\t.reference\t"; break4 ; |
650 | 447 | case MCSA_Weak: OS << MAI->getWeakDirective(); break; |
651 | 176 | case MCSA_WeakDefinition: |
652 | 176 | OS << "\t.weak_definition\t"; |
653 | 176 | break; |
654 | 77 | // .weak_reference |
655 | 155 | case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break; |
656 | 77 | case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break20 ; |
657 | 77 | case MCSA_Cold: |
658 | 0 | // Assemblers currently do not support a .cold directive. |
659 | 0 | return false; |
660 | 232k | } |
661 | 232k | |
662 | 232k | Symbol->print(OS, MAI); |
663 | 232k | EmitEOL(); |
664 | 232k | |
665 | 232k | return true; |
666 | 232k | } |
667 | | |
668 | 3 | void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { |
669 | 3 | OS << ".desc" << ' '; |
670 | 3 | Symbol->print(OS, MAI); |
671 | 3 | OS << ',' << DescValue; |
672 | 3 | EmitEOL(); |
673 | 3 | } |
674 | | |
675 | 7.86k | void MCAsmStreamer::EmitSyntaxDirective() { |
676 | 7.86k | if (MAI->getAssemblerDialect() == 1) { |
677 | 19 | OS << "\t.intel_syntax noprefix"; |
678 | 19 | EmitEOL(); |
679 | 19 | } |
680 | 7.86k | // FIXME: Currently emit unprefix'ed registers. |
681 | 7.86k | // The intel_syntax directive has one optional argument |
682 | 7.86k | // with may have a value of prefix or noprefix. |
683 | 7.86k | } |
684 | | |
685 | 3.55k | void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { |
686 | 3.55k | OS << "\t.def\t "; |
687 | 3.55k | Symbol->print(OS, MAI); |
688 | 3.55k | OS << ';'; |
689 | 3.55k | EmitEOL(); |
690 | 3.55k | } |
691 | | |
692 | 3.55k | void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) { |
693 | 3.55k | OS << "\t.scl\t" << StorageClass << ';'; |
694 | 3.55k | EmitEOL(); |
695 | 3.55k | } |
696 | | |
697 | 3.55k | void MCAsmStreamer::EmitCOFFSymbolType (int Type) { |
698 | 3.55k | OS << "\t.type\t" << Type << ';'; |
699 | 3.55k | EmitEOL(); |
700 | 3.55k | } |
701 | | |
702 | 3.55k | void MCAsmStreamer::EndCOFFSymbolDef() { |
703 | 3.55k | OS << "\t.endef"; |
704 | 3.55k | EmitEOL(); |
705 | 3.55k | } |
706 | | |
707 | 30 | void MCAsmStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { |
708 | 30 | OS << "\t.safeseh\t"; |
709 | 30 | Symbol->print(OS, MAI); |
710 | 30 | EmitEOL(); |
711 | 30 | } |
712 | | |
713 | 4 | void MCAsmStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) { |
714 | 4 | OS << "\t.symidx\t"; |
715 | 4 | Symbol->print(OS, MAI); |
716 | 4 | EmitEOL(); |
717 | 4 | } |
718 | | |
719 | 269 | void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { |
720 | 269 | OS << "\t.secidx\t"; |
721 | 269 | Symbol->print(OS, MAI); |
722 | 269 | EmitEOL(); |
723 | 269 | } |
724 | | |
725 | 456 | void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) { |
726 | 456 | OS << "\t.secrel32\t"; |
727 | 456 | Symbol->print(OS, MAI); |
728 | 456 | if (Offset != 0) |
729 | 2 | OS << '+' << Offset; |
730 | 456 | EmitEOL(); |
731 | 456 | } |
732 | | |
733 | 0 | void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) { |
734 | 0 | OS << "\t.rva\t"; |
735 | 0 | Symbol->print(OS, MAI); |
736 | 0 | if (Offset > 0) |
737 | 0 | OS << '+' << Offset; |
738 | 0 | else if (Offset < 0) |
739 | 0 | OS << '-' << -Offset; |
740 | 0 | EmitEOL(); |
741 | 0 | } |
742 | | |
743 | 205k | void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { |
744 | 205k | assert(MAI->hasDotTypeDotSizeDirective()); |
745 | 205k | OS << "\t.size\t"; |
746 | 205k | Symbol->print(OS, MAI); |
747 | 205k | OS << ", "; |
748 | 205k | Value->print(OS, MAI); |
749 | 205k | EmitEOL(); |
750 | 205k | } |
751 | | |
752 | | void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
753 | 3.09k | unsigned ByteAlignment) { |
754 | 3.09k | OS << "\t.comm\t"; |
755 | 3.09k | Symbol->print(OS, MAI); |
756 | 3.09k | OS << ',' << Size; |
757 | 3.09k | |
758 | 3.09k | if (ByteAlignment != 0) { |
759 | 2.98k | if (MAI->getCOMMDirectiveAlignmentIsInBytes()) |
760 | 2.74k | OS << ',' << ByteAlignment; |
761 | 240 | else |
762 | 240 | OS << ',' << Log2_32(ByteAlignment); |
763 | 2.98k | } |
764 | 3.09k | EmitEOL(); |
765 | 3.09k | } |
766 | | |
767 | | void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
768 | 49 | unsigned ByteAlign) { |
769 | 49 | OS << "\t.lcomm\t"; |
770 | 49 | Symbol->print(OS, MAI); |
771 | 49 | OS << ',' << Size; |
772 | 49 | |
773 | 49 | if (ByteAlign > 1) { |
774 | 39 | switch (MAI->getLCOMMDirectiveAlignmentType()) { |
775 | 39 | case LCOMM::NoAlignment: |
776 | 0 | llvm_unreachable("alignment not supported on .lcomm!"); |
777 | 39 | case LCOMM::ByteAlignment: |
778 | 38 | OS << ',' << ByteAlign; |
779 | 38 | break; |
780 | 39 | case LCOMM::Log2Alignment: |
781 | 1 | assert(isPowerOf2_32(ByteAlign) && "alignment must be a power of 2"); |
782 | 1 | OS << ',' << Log2_32(ByteAlign); |
783 | 1 | break; |
784 | 49 | } |
785 | 49 | } |
786 | 49 | EmitEOL(); |
787 | 49 | } |
788 | | |
789 | | void MCAsmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, |
790 | | uint64_t Size, unsigned ByteAlignment, |
791 | 303 | SMLoc Loc) { |
792 | 303 | if (Symbol) |
793 | 302 | AssignFragment(Symbol, &Section->getDummyFragment()); |
794 | 303 | |
795 | 303 | // Note: a .zerofill directive does not switch sections. |
796 | 303 | OS << ".zerofill "; |
797 | 303 | |
798 | 303 | assert(Section->getVariant() == MCSection::SV_MachO && |
799 | 303 | ".zerofill is a Mach-O specific directive"); |
800 | 303 | // This is a mach-o specific directive. |
801 | 303 | |
802 | 303 | const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); |
803 | 303 | OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); |
804 | 303 | |
805 | 303 | if (Symbol) { |
806 | 302 | OS << ','; |
807 | 302 | Symbol->print(OS, MAI); |
808 | 302 | OS << ',' << Size; |
809 | 302 | if (ByteAlignment != 0) |
810 | 302 | OS << ',' << Log2_32(ByteAlignment); |
811 | 302 | } |
812 | 303 | EmitEOL(); |
813 | 303 | } |
814 | | |
815 | | // .tbss sym, size, align |
816 | | // This depends that the symbol has already been mangled from the original, |
817 | | // e.g. _a. |
818 | | void MCAsmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, |
819 | 73 | uint64_t Size, unsigned ByteAlignment) { |
820 | 73 | AssignFragment(Symbol, &Section->getDummyFragment()); |
821 | 73 | |
822 | 73 | assert(Symbol && "Symbol shouldn't be NULL!"); |
823 | 73 | // Instead of using the Section we'll just use the shortcut. |
824 | 73 | |
825 | 73 | assert(Section->getVariant() == MCSection::SV_MachO && |
826 | 73 | ".zerofill is a Mach-O specific directive"); |
827 | 73 | // This is a mach-o specific directive and section. |
828 | 73 | |
829 | 73 | OS << ".tbss "; |
830 | 73 | Symbol->print(OS, MAI); |
831 | 73 | OS << ", " << Size; |
832 | 73 | |
833 | 73 | // Output align if we have it. We default to 1 so don't bother printing |
834 | 73 | // that. |
835 | 73 | if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment)42 ; |
836 | 73 | |
837 | 73 | EmitEOL(); |
838 | 73 | } |
839 | | |
840 | 12.6k | static inline char toOctal(int X) { return (X&7)+'0'; } |
841 | | |
842 | 33.0k | static void PrintQuotedString(StringRef Data, raw_ostream &OS) { |
843 | 33.0k | OS << '"'; |
844 | 33.0k | |
845 | 724k | for (unsigned i = 0, e = Data.size(); i != e; ++i691k ) { |
846 | 691k | unsigned char C = Data[i]; |
847 | 691k | if (C == '"' || C == '\\'691k ) { |
848 | 833 | OS << '\\' << (char)C; |
849 | 833 | continue; |
850 | 833 | } |
851 | 690k | |
852 | 690k | if (isPrint((unsigned char)C)) { |
853 | 685k | OS << (char)C; |
854 | 685k | continue; |
855 | 685k | } |
856 | 4.78k | |
857 | 4.78k | switch (C) { |
858 | 4.78k | case '\b': OS << "\\b"; break73 ; |
859 | 4.78k | case '\f': OS << "\\f"; break11 ; |
860 | 4.78k | case '\n': OS << "\\n"; break405 ; |
861 | 4.78k | case '\r': OS << "\\r"; break7 ; |
862 | 4.78k | case '\t': OS << "\\t"; break68 ; |
863 | 4.78k | default: |
864 | 4.21k | OS << '\\'; |
865 | 4.21k | OS << toOctal(C >> 6); |
866 | 4.21k | OS << toOctal(C >> 3); |
867 | 4.21k | OS << toOctal(C >> 0); |
868 | 4.21k | break; |
869 | 4.78k | } |
870 | 4.78k | } |
871 | 33.0k | |
872 | 33.0k | OS << '"'; |
873 | 33.0k | } |
874 | | |
875 | 67.4k | void MCAsmStreamer::EmitBytes(StringRef Data) { |
876 | 67.4k | assert(getCurrentSectionOnly() && |
877 | 67.4k | "Cannot emit contents before setting section!"); |
878 | 67.4k | if (Data.empty()) return139 ; |
879 | 67.3k | |
880 | 67.3k | // If only single byte is provided or no ascii or asciz directives is |
881 | 67.3k | // supported, emit as vector of 8bits data. |
882 | 67.3k | if (Data.size() == 1 || |
883 | 67.3k | !(15.7k MAI->getAscizDirective()15.7k || MAI->getAsciiDirective()449 )) { |
884 | 52.0k | if (MCTargetStreamer *TS = getTargetStreamer()) { |
885 | 40.0k | TS->emitRawBytes(Data); |
886 | 40.0k | } else { |
887 | 11.9k | const char *Directive = MAI->getData8bitsDirective(); |
888 | 11.9k | for (const unsigned char C : Data.bytes()) { |
889 | 11.9k | OS << Directive << (unsigned)C; |
890 | 11.9k | EmitEOL(); |
891 | 11.9k | } |
892 | 11.9k | } |
893 | 52.0k | return; |
894 | 52.0k | } |
895 | 15.3k | |
896 | 15.3k | // If the data ends with 0 and the target supports .asciz, use it, otherwise |
897 | 15.3k | // use .ascii |
898 | 15.3k | if (MAI->getAscizDirective() && Data.back() == 0) { |
899 | 13.2k | OS << MAI->getAscizDirective(); |
900 | 13.2k | Data = Data.substr(0, Data.size()-1); |
901 | 13.2k | } else { |
902 | 2.07k | OS << MAI->getAsciiDirective(); |
903 | 2.07k | } |
904 | 15.3k | |
905 | 15.3k | PrintQuotedString(Data, OS); |
906 | 15.3k | EmitEOL(); |
907 | 15.3k | } |
908 | | |
909 | 423 | void MCAsmStreamer::EmitBinaryData(StringRef Data) { |
910 | 423 | // This is binary data. Print it in a grid of hex bytes for readability. |
911 | 423 | const size_t Cols = 4; |
912 | 875 | for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols452 ) { |
913 | 452 | size_t J = I, EJ = std::min(I + Cols, Data.size()); |
914 | 452 | assert(EJ > 0); |
915 | 452 | OS << MAI->getData8bitsDirective(); |
916 | 624 | for (; J < EJ - 1; ++J172 ) |
917 | 172 | OS << format("0x%02x", uint8_t(Data[J])) << ", "; |
918 | 452 | OS << format("0x%02x", uint8_t(Data[J])); |
919 | 452 | EmitEOL(); |
920 | 452 | } |
921 | 423 | } |
922 | | |
923 | 575k | void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) { |
924 | 575k | EmitValue(MCConstantExpr::create(Value, getContext()), Size); |
925 | 575k | } |
926 | | |
927 | 26.3k | void MCAsmStreamer::EmitIntValueInHex(uint64_t Value, unsigned Size) { |
928 | 26.3k | EmitValue(MCConstantExpr::create(Value, getContext(), true), Size); |
929 | 26.3k | } |
930 | | |
931 | | void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, |
932 | 632k | SMLoc Loc) { |
933 | 632k | assert(Size <= 8 && "Invalid size"); |
934 | 632k | assert(getCurrentSectionOnly() && |
935 | 632k | "Cannot emit contents before setting section!"); |
936 | 632k | const char *Directive = nullptr; |
937 | 632k | switch (Size) { |
938 | 632k | default: break0 ; |
939 | 632k | case 1: Directive = MAI->getData8bitsDirective(); break153k ; |
940 | 632k | case 2: Directive = MAI->getData16bitsDirective(); break99.2k ; |
941 | 632k | case 4: Directive = MAI->getData32bitsDirective(); break331k ; |
942 | 632k | case 8: Directive = MAI->getData64bitsDirective(); break47.7k ; |
943 | 632k | } |
944 | 632k | |
945 | 632k | if (!Directive) { |
946 | 823 | int64_t IntValue; |
947 | 823 | if (!Value->evaluateAsAbsolute(IntValue)) |
948 | 0 | report_fatal_error("Don't know how to emit this value."); |
949 | 823 | |
950 | 823 | // We couldn't handle the requested integer size so we fallback by breaking |
951 | 823 | // the request down into several, smaller, integers. |
952 | 823 | // Since sizes greater or equal to "Size" are invalid, we use the greatest |
953 | 823 | // power of 2 that is less than "Size" as our largest piece of granularity. |
954 | 823 | bool IsLittleEndian = MAI->isLittleEndian(); |
955 | 2.46k | for (unsigned Emitted = 0; Emitted != Size;) { |
956 | 1.64k | unsigned Remaining = Size - Emitted; |
957 | 1.64k | // The size of our partial emission must be a power of two less than |
958 | 1.64k | // Size. |
959 | 1.64k | unsigned EmissionSize = PowerOf2Floor(std::min(Remaining, Size - 1)); |
960 | 1.64k | // Calculate the byte offset of our partial emission taking into account |
961 | 1.64k | // the endianness of the target. |
962 | 1.64k | unsigned ByteOffset = |
963 | 1.64k | IsLittleEndian ? Emitted1.49k : (Remaining - EmissionSize)154 ; |
964 | 1.64k | uint64_t ValueToEmit = IntValue >> (ByteOffset * 8); |
965 | 1.64k | // We truncate our partial emission to fit within the bounds of the |
966 | 1.64k | // emission domain. This produces nicer output and silences potential |
967 | 1.64k | // truncation warnings when round tripping through another assembler. |
968 | 1.64k | uint64_t Shift = 64 - EmissionSize * 8; |
969 | 1.64k | assert(Shift < static_cast<uint64_t>( |
970 | 1.64k | std::numeric_limits<unsigned long long>::digits) && |
971 | 1.64k | "undefined behavior"); |
972 | 1.64k | ValueToEmit &= ~0ULL >> Shift; |
973 | 1.64k | EmitIntValue(ValueToEmit, EmissionSize); |
974 | 1.64k | Emitted += EmissionSize; |
975 | 1.64k | } |
976 | 823 | return; |
977 | 823 | } |
978 | 631k | |
979 | 631k | assert(Directive && "Invalid size for machine code value!"); |
980 | 631k | OS << Directive; |
981 | 631k | if (MCTargetStreamer *TS = getTargetStreamer()) { |
982 | 604k | TS->emitValue(Value); |
983 | 604k | } else { |
984 | 26.8k | Value->print(OS, MAI); |
985 | 26.8k | EmitEOL(); |
986 | 26.8k | } |
987 | 631k | } |
988 | | |
989 | 2.23k | void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) { |
990 | 2.23k | int64_t IntValue; |
991 | 2.23k | if (Value->evaluateAsAbsolute(IntValue)) { |
992 | 4 | EmitULEB128IntValue(IntValue); |
993 | 4 | return; |
994 | 4 | } |
995 | 2.23k | OS << "\t.uleb128 "; |
996 | 2.23k | Value->print(OS, MAI); |
997 | 2.23k | EmitEOL(); |
998 | 2.23k | } |
999 | | |
1000 | 4 | void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { |
1001 | 4 | int64_t IntValue; |
1002 | 4 | if (Value->evaluateAsAbsolute(IntValue)) { |
1003 | 4 | EmitSLEB128IntValue(IntValue); |
1004 | 4 | return; |
1005 | 4 | } |
1006 | 0 | OS << "\t.sleb128 "; |
1007 | 0 | Value->print(OS, MAI); |
1008 | 0 | EmitEOL(); |
1009 | 0 | } |
1010 | | |
1011 | 3 | void MCAsmStreamer::EmitDTPRel64Value(const MCExpr *Value) { |
1012 | 3 | assert(MAI->getDTPRel64Directive() != nullptr); |
1013 | 3 | OS << MAI->getDTPRel64Directive(); |
1014 | 3 | Value->print(OS, MAI); |
1015 | 3 | EmitEOL(); |
1016 | 3 | } |
1017 | | |
1018 | 3 | void MCAsmStreamer::EmitDTPRel32Value(const MCExpr *Value) { |
1019 | 3 | assert(MAI->getDTPRel32Directive() != nullptr); |
1020 | 3 | OS << MAI->getDTPRel32Directive(); |
1021 | 3 | Value->print(OS, MAI); |
1022 | 3 | EmitEOL(); |
1023 | 3 | } |
1024 | | |
1025 | 2 | void MCAsmStreamer::EmitTPRel64Value(const MCExpr *Value) { |
1026 | 2 | assert(MAI->getTPRel64Directive() != nullptr); |
1027 | 2 | OS << MAI->getTPRel64Directive(); |
1028 | 2 | Value->print(OS, MAI); |
1029 | 2 | EmitEOL(); |
1030 | 2 | } |
1031 | | |
1032 | 2 | void MCAsmStreamer::EmitTPRel32Value(const MCExpr *Value) { |
1033 | 2 | assert(MAI->getTPRel32Directive() != nullptr); |
1034 | 2 | OS << MAI->getTPRel32Directive(); |
1035 | 2 | Value->print(OS, MAI); |
1036 | 2 | EmitEOL(); |
1037 | 2 | } |
1038 | | |
1039 | 33 | void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { |
1040 | 33 | assert(MAI->getGPRel64Directive() != nullptr); |
1041 | 33 | OS << MAI->getGPRel64Directive(); |
1042 | 33 | Value->print(OS, MAI); |
1043 | 33 | EmitEOL(); |
1044 | 33 | } |
1045 | | |
1046 | 23 | void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { |
1047 | 23 | assert(MAI->getGPRel32Directive() != nullptr); |
1048 | 23 | OS << MAI->getGPRel32Directive(); |
1049 | 23 | Value->print(OS, MAI); |
1050 | 23 | EmitEOL(); |
1051 | 23 | } |
1052 | | |
1053 | | void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, |
1054 | 74.5k | SMLoc Loc) { |
1055 | 74.5k | int64_t IntNumBytes; |
1056 | 74.5k | if (NumBytes.evaluateAsAbsolute(IntNumBytes) && IntNumBytes == 074.5k ) |
1057 | 52.2k | return; |
1058 | 22.3k | |
1059 | 22.3k | if (const char *ZeroDirective = MAI->getZeroDirective()) { |
1060 | 22.3k | // FIXME: Emit location directives |
1061 | 22.3k | OS << ZeroDirective; |
1062 | 22.3k | NumBytes.print(OS, MAI); |
1063 | 22.3k | if (FillValue != 0) |
1064 | 3.43k | OS << ',' << (int)FillValue; |
1065 | 22.3k | EmitEOL(); |
1066 | 22.3k | return; |
1067 | 22.3k | } |
1068 | 0 | |
1069 | 0 | MCStreamer::emitFill(NumBytes, FillValue); |
1070 | 0 | } |
1071 | | |
1072 | | void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size, |
1073 | 24 | int64_t Expr, SMLoc Loc) { |
1074 | 24 | // FIXME: Emit location directives |
1075 | 24 | OS << "\t.fill\t"; |
1076 | 24 | NumValues.print(OS, MAI); |
1077 | 24 | OS << ", " << Size << ", 0x"; |
1078 | 24 | OS.write_hex(truncateToSize(Expr, 4)); |
1079 | 24 | EmitEOL(); |
1080 | 24 | } |
1081 | | |
1082 | | void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, |
1083 | | unsigned ValueSize, |
1084 | 264k | unsigned MaxBytesToEmit) { |
1085 | 264k | // Some assemblers don't support non-power of two alignments, so we always |
1086 | 264k | // emit alignments as a power of two if possible. |
1087 | 264k | if (isPowerOf2_32(ByteAlignment)) { |
1088 | 264k | switch (ValueSize) { |
1089 | 264k | default: |
1090 | 0 | llvm_unreachable("Invalid size for machine code value!"); |
1091 | 264k | case 1: |
1092 | 263k | OS << "\t.p2align\t"; |
1093 | 263k | break; |
1094 | 264k | case 2: |
1095 | 4 | OS << ".p2alignw "; |
1096 | 4 | break; |
1097 | 264k | case 4: |
1098 | 7 | OS << ".p2alignl "; |
1099 | 7 | break; |
1100 | 264k | case 8: |
1101 | 0 | llvm_unreachable("Unsupported alignment size!"); |
1102 | 264k | } |
1103 | 264k | |
1104 | 264k | OS << Log2_32(ByteAlignment); |
1105 | 264k | |
1106 | 264k | if (Value || MaxBytesToEmit150k ) { |
1107 | 113k | OS << ", 0x"; |
1108 | 113k | OS.write_hex(truncateToSize(Value, ValueSize)); |
1109 | 113k | |
1110 | 113k | if (MaxBytesToEmit) |
1111 | 1 | OS << ", " << MaxBytesToEmit; |
1112 | 113k | } |
1113 | 264k | EmitEOL(); |
1114 | 264k | return; |
1115 | 264k | } |
1116 | 2 | |
1117 | 2 | // Non-power of two alignment. This is not widely supported by assemblers. |
1118 | 2 | // FIXME: Parameterize this based on MAI. |
1119 | 2 | switch (ValueSize) { |
1120 | 2 | default: 0 llvm_unreachable0 ("Invalid size for machine code value!"); |
1121 | 2 | case 1: OS << ".balign"; break; |
1122 | 2 | case 2: OS << ".balignw"; break0 ; |
1123 | 2 | case 4: OS << ".balignl"; break0 ; |
1124 | 2 | case 8: 0 llvm_unreachable0 ("Unsupported alignment size!"); |
1125 | 2 | } |
1126 | 2 | |
1127 | 2 | OS << ' ' << ByteAlignment; |
1128 | 2 | OS << ", " << truncateToSize(Value, ValueSize); |
1129 | 2 | if (MaxBytesToEmit) |
1130 | 0 | OS << ", " << MaxBytesToEmit; |
1131 | 2 | EmitEOL(); |
1132 | 2 | } |
1133 | | |
1134 | | void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, |
1135 | 220k | unsigned MaxBytesToEmit) { |
1136 | 220k | // Emit with a text fill value. |
1137 | 220k | EmitValueToAlignment(ByteAlignment, MAI->getTextAlignFillValue(), |
1138 | 220k | 1, MaxBytesToEmit); |
1139 | 220k | } |
1140 | | |
1141 | | void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset, |
1142 | | unsigned char Value, |
1143 | 9 | SMLoc Loc) { |
1144 | 9 | // FIXME: Verify that Offset is associated with the current section. |
1145 | 9 | OS << ".org "; |
1146 | 9 | Offset->print(OS, MAI); |
1147 | 9 | OS << ", " << (unsigned)Value; |
1148 | 9 | EmitEOL(); |
1149 | 9 | } |
1150 | | |
1151 | 16.2k | void MCAsmStreamer::EmitFileDirective(StringRef Filename) { |
1152 | 16.2k | assert(MAI->hasSingleParameterDotFile()); |
1153 | 16.2k | OS << "\t.file\t"; |
1154 | 16.2k | PrintQuotedString(Filename, OS); |
1155 | 16.2k | EmitEOL(); |
1156 | 16.2k | } |
1157 | | |
1158 | | static void printDwarfFileDirective(unsigned FileNo, StringRef Directory, |
1159 | | StringRef Filename, |
1160 | | Optional<MD5::MD5Result> Checksum, |
1161 | | Optional<StringRef> Source, |
1162 | | bool UseDwarfDirectory, |
1163 | 536 | raw_svector_ostream &OS) { |
1164 | 536 | SmallString<128> FullPathName; |
1165 | 536 | |
1166 | 536 | if (!UseDwarfDirectory && !Directory.empty()486 ) { |
1167 | 450 | if (sys::path::is_absolute(Filename)) |
1168 | 52 | Directory = ""; |
1169 | 398 | else { |
1170 | 398 | FullPathName = Directory; |
1171 | 398 | sys::path::append(FullPathName, Filename); |
1172 | 398 | Directory = ""; |
1173 | 398 | Filename = FullPathName; |
1174 | 398 | } |
1175 | 450 | } |
1176 | 536 | |
1177 | 536 | OS << "\t.file\t" << FileNo << ' '; |
1178 | 536 | if (!Directory.empty()) { |
1179 | 42 | PrintQuotedString(Directory, OS); |
1180 | 42 | OS << ' '; |
1181 | 42 | } |
1182 | 536 | PrintQuotedString(Filename, OS); |
1183 | 536 | if (Checksum) |
1184 | 11 | OS << " md5 0x" << Checksum->digest(); |
1185 | 536 | if (Source) { |
1186 | 8 | OS << " source "; |
1187 | 8 | PrintQuotedString(*Source, OS); |
1188 | 8 | } |
1189 | 536 | } |
1190 | | |
1191 | | Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective( |
1192 | | unsigned FileNo, StringRef Directory, StringRef Filename, |
1193 | 4.14k | Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source, unsigned CUID) { |
1194 | 4.14k | assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer"); |
1195 | 4.14k | |
1196 | 4.14k | MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); |
1197 | 4.14k | unsigned NumFiles = Table.getMCDwarfFiles().size(); |
1198 | 4.14k | Expected<unsigned> FileNoOrErr = |
1199 | 4.14k | Table.tryGetFile(Directory, Filename, Checksum, Source, |
1200 | 4.14k | getContext().getDwarfVersion(), FileNo); |
1201 | 4.14k | if (!FileNoOrErr) |
1202 | 0 | return FileNoOrErr.takeError(); |
1203 | 4.14k | FileNo = FileNoOrErr.get(); |
1204 | 4.14k | if (NumFiles == Table.getMCDwarfFiles().size()) |
1205 | 3.62k | return FileNo; |
1206 | 525 | |
1207 | 525 | SmallString<128> Str; |
1208 | 525 | raw_svector_ostream OS1(Str); |
1209 | 525 | printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source, |
1210 | 525 | UseDwarfDirectory, OS1); |
1211 | 525 | |
1212 | 525 | if (MCTargetStreamer *TS = getTargetStreamer()) |
1213 | 400 | TS->emitDwarfFileDirective(OS1.str()); |
1214 | 125 | else |
1215 | 125 | EmitRawText(OS1.str()); |
1216 | 525 | |
1217 | 525 | return FileNo; |
1218 | 525 | } |
1219 | | |
1220 | | void MCAsmStreamer::emitDwarfFile0Directive(StringRef Directory, |
1221 | | StringRef Filename, |
1222 | | Optional<MD5::MD5Result> Checksum, |
1223 | | Optional<StringRef> Source, |
1224 | 438 | unsigned CUID) { |
1225 | 438 | assert(CUID == 0); |
1226 | 438 | // .file 0 is new for DWARF v5. |
1227 | 438 | if (getContext().getDwarfVersion() < 5) |
1228 | 427 | return; |
1229 | 11 | // Inform MCDwarf about the root file. |
1230 | 11 | getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum, |
1231 | 11 | Source); |
1232 | 11 | |
1233 | 11 | SmallString<128> Str; |
1234 | 11 | raw_svector_ostream OS1(Str); |
1235 | 11 | printDwarfFileDirective(0, Directory, Filename, Checksum, Source, |
1236 | 11 | UseDwarfDirectory, OS1); |
1237 | 11 | |
1238 | 11 | if (MCTargetStreamer *TS = getTargetStreamer()) |
1239 | 9 | TS->emitDwarfFileDirective(OS1.str()); |
1240 | 2 | else |
1241 | 2 | EmitRawText(OS1.str()); |
1242 | 11 | } |
1243 | | |
1244 | | void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, |
1245 | | unsigned Column, unsigned Flags, |
1246 | | unsigned Isa, |
1247 | | unsigned Discriminator, |
1248 | 1.83k | StringRef FileName) { |
1249 | 1.83k | OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; |
1250 | 1.83k | if (MAI->supportsExtendedDwarfLocDirective()) { |
1251 | 1.76k | if (Flags & DWARF2_FLAG_BASIC_BLOCK) |
1252 | 1.76k | OS << " basic_block"0 ; |
1253 | 1.76k | if (Flags & DWARF2_FLAG_PROLOGUE_END) |
1254 | 1.76k | OS << " prologue_end"407 ; |
1255 | 1.76k | if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) |
1256 | 1.76k | OS << " epilogue_begin"0 ; |
1257 | 1.76k | |
1258 | 1.76k | unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); |
1259 | 1.76k | if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { |
1260 | 387 | OS << " is_stmt "; |
1261 | 387 | |
1262 | 387 | if (Flags & DWARF2_FLAG_IS_STMT) |
1263 | 387 | OS << "1"153 ; |
1264 | 234 | else |
1265 | 234 | OS << "0"; |
1266 | 387 | } |
1267 | 1.76k | |
1268 | 1.76k | if (Isa) |
1269 | 1 | OS << " isa " << Isa; |
1270 | 1.76k | if (Discriminator) |
1271 | 15 | OS << " discriminator " << Discriminator; |
1272 | 1.76k | } |
1273 | 1.83k | |
1274 | 1.83k | if (IsVerboseAsm) { |
1275 | 1.68k | OS.PadToColumn(MAI->getCommentColumn()); |
1276 | 1.68k | OS << MAI->getCommentString() << ' ' << FileName << ':' |
1277 | 1.68k | << Line << ':' << Column; |
1278 | 1.68k | } |
1279 | 1.83k | EmitEOL(); |
1280 | 1.83k | this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, |
1281 | 1.83k | Isa, Discriminator, FileName); |
1282 | 1.83k | } |
1283 | | |
1284 | 461 | MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) { |
1285 | 461 | // Always use the zeroth line table, since asm syntax only supports one line |
1286 | 461 | // table for now. |
1287 | 461 | return MCStreamer::getDwarfLineTableSymbol(0); |
1288 | 461 | } |
1289 | | |
1290 | | bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename, |
1291 | | ArrayRef<uint8_t> Checksum, |
1292 | 106 | unsigned ChecksumKind) { |
1293 | 106 | if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum, |
1294 | 106 | ChecksumKind)) |
1295 | 0 | return false; |
1296 | 106 | |
1297 | 106 | OS << "\t.cv_file\t" << FileNo << ' '; |
1298 | 106 | PrintQuotedString(Filename, OS); |
1299 | 106 | |
1300 | 106 | if (!ChecksumKind) { |
1301 | 50 | EmitEOL(); |
1302 | 50 | return true; |
1303 | 50 | } |
1304 | 56 | |
1305 | 56 | OS << ' '; |
1306 | 56 | PrintQuotedString(toHex(Checksum), OS); |
1307 | 56 | OS << ' ' << ChecksumKind; |
1308 | 56 | |
1309 | 56 | EmitEOL(); |
1310 | 56 | return true; |
1311 | 56 | } |
1312 | | |
1313 | 210 | bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) { |
1314 | 210 | OS << "\t.cv_func_id " << FuncId << '\n'; |
1315 | 210 | return MCStreamer::EmitCVFuncIdDirective(FuncId); |
1316 | 210 | } |
1317 | | |
1318 | | bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, |
1319 | | unsigned IAFunc, |
1320 | | unsigned IAFile, |
1321 | | unsigned IALine, unsigned IACol, |
1322 | 15 | SMLoc Loc) { |
1323 | 15 | OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc |
1324 | 15 | << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n'; |
1325 | 15 | return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, |
1326 | 15 | IALine, IACol, Loc); |
1327 | 15 | } |
1328 | | |
1329 | | void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, |
1330 | | unsigned Line, unsigned Column, |
1331 | | bool PrologueEnd, bool IsStmt, |
1332 | 696 | StringRef FileName, SMLoc Loc) { |
1333 | 696 | // Validate the directive. |
1334 | 696 | if (!checkCVLocSection(FunctionId, FileNo, Loc)) |
1335 | 1 | return; |
1336 | 695 | |
1337 | 695 | OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " " |
1338 | 695 | << Column; |
1339 | 695 | if (PrologueEnd) |
1340 | 0 | OS << " prologue_end"; |
1341 | 695 | |
1342 | 695 | if (IsStmt) |
1343 | 0 | OS << " is_stmt 1"; |
1344 | 695 | |
1345 | 695 | if (IsVerboseAsm) { |
1346 | 695 | OS.PadToColumn(MAI->getCommentColumn()); |
1347 | 695 | OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':' |
1348 | 695 | << Column; |
1349 | 695 | } |
1350 | 695 | EmitEOL(); |
1351 | 695 | } |
1352 | | |
1353 | | void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, |
1354 | | const MCSymbol *FnStart, |
1355 | 204 | const MCSymbol *FnEnd) { |
1356 | 204 | OS << "\t.cv_linetable\t" << FunctionId << ", "; |
1357 | 204 | FnStart->print(OS, MAI); |
1358 | 204 | OS << ", "; |
1359 | 204 | FnEnd->print(OS, MAI); |
1360 | 204 | EmitEOL(); |
1361 | 204 | this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd); |
1362 | 204 | } |
1363 | | |
1364 | | void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, |
1365 | | unsigned SourceFileId, |
1366 | | unsigned SourceLineNum, |
1367 | | const MCSymbol *FnStartSym, |
1368 | 13 | const MCSymbol *FnEndSym) { |
1369 | 13 | OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId |
1370 | 13 | << ' ' << SourceLineNum << ' '; |
1371 | 13 | FnStartSym->print(OS, MAI); |
1372 | 13 | OS << ' '; |
1373 | 13 | FnEndSym->print(OS, MAI); |
1374 | 13 | EmitEOL(); |
1375 | 13 | this->MCStreamer::EmitCVInlineLinetableDirective( |
1376 | 13 | PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); |
1377 | 13 | } |
1378 | | |
1379 | | void MCAsmStreamer::EmitCVDefRangeDirective( |
1380 | | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
1381 | 270 | StringRef FixedSizePortion) { |
1382 | 270 | OS << "\t.cv_def_range\t"; |
1383 | 272 | for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) { |
1384 | 272 | OS << ' '; |
1385 | 272 | Range.first->print(OS, MAI); |
1386 | 272 | OS << ' '; |
1387 | 272 | Range.second->print(OS, MAI); |
1388 | 272 | } |
1389 | 270 | OS << ", "; |
1390 | 270 | PrintQuotedString(FixedSizePortion, OS); |
1391 | 270 | EmitEOL(); |
1392 | 270 | this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); |
1393 | 270 | } |
1394 | | |
1395 | 112 | void MCAsmStreamer::EmitCVStringTableDirective() { |
1396 | 112 | OS << "\t.cv_stringtable"; |
1397 | 112 | EmitEOL(); |
1398 | 112 | } |
1399 | | |
1400 | 110 | void MCAsmStreamer::EmitCVFileChecksumsDirective() { |
1401 | 110 | OS << "\t.cv_filechecksums"; |
1402 | 110 | EmitEOL(); |
1403 | 110 | } |
1404 | | |
1405 | 12 | void MCAsmStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) { |
1406 | 12 | OS << "\t.cv_filechecksumoffset\t" << FileNo; |
1407 | 12 | EmitEOL(); |
1408 | 12 | } |
1409 | | |
1410 | 83 | void MCAsmStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) { |
1411 | 83 | OS << "\t.cv_fpo_data\t"; |
1412 | 83 | ProcSym->print(OS, MAI); |
1413 | 83 | EmitEOL(); |
1414 | 83 | } |
1415 | | |
1416 | 356 | void MCAsmStreamer::EmitIdent(StringRef IdentString) { |
1417 | 356 | assert(MAI->hasIdentDirective() && ".ident directive not supported"); |
1418 | 356 | OS << "\t.ident\t"; |
1419 | 356 | PrintQuotedString(IdentString, OS); |
1420 | 356 | EmitEOL(); |
1421 | 356 | } |
1422 | | |
1423 | 177 | void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) { |
1424 | 177 | MCStreamer::EmitCFISections(EH, Debug); |
1425 | 177 | OS << "\t.cfi_sections "; |
1426 | 177 | if (EH) { |
1427 | 0 | OS << ".eh_frame"; |
1428 | 0 | if (Debug) |
1429 | 0 | OS << ", .debug_frame"; |
1430 | 177 | } else if (Debug) { |
1431 | 177 | OS << ".debug_frame"; |
1432 | 177 | } |
1433 | 177 | |
1434 | 177 | EmitEOL(); |
1435 | 177 | } |
1436 | | |
1437 | 114k | void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { |
1438 | 114k | OS << "\t.cfi_startproc"; |
1439 | 114k | if (Frame.IsSimple) |
1440 | 2 | OS << " simple"; |
1441 | 114k | EmitEOL(); |
1442 | 114k | } |
1443 | | |
1444 | 114k | void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { |
1445 | 114k | MCStreamer::EmitCFIEndProcImpl(Frame); |
1446 | 114k | OS << "\t.cfi_endproc"; |
1447 | 114k | EmitEOL(); |
1448 | 114k | } |
1449 | | |
1450 | 25.8k | void MCAsmStreamer::EmitRegisterName(int64_t Register) { |
1451 | 25.8k | if (!MAI->useDwarfRegNumForCFI()) { |
1452 | 22.7k | // User .cfi_* directives can use arbitrary DWARF register numbers, not |
1453 | 22.7k | // just ones that map to LLVM register numbers and have known names. |
1454 | 22.7k | // Fall back to using the original number directly if no name is known. |
1455 | 22.7k | const MCRegisterInfo *MRI = getContext().getRegisterInfo(); |
1456 | 22.7k | int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); |
1457 | 22.7k | if (LLVMRegister != -1) { |
1458 | 22.7k | InstPrinter->printRegName(OS, LLVMRegister); |
1459 | 22.7k | return; |
1460 | 22.7k | } |
1461 | 3.09k | } |
1462 | 3.09k | OS << Register; |
1463 | 3.09k | } |
1464 | | |
1465 | 2.42k | void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { |
1466 | 2.42k | MCStreamer::EmitCFIDefCfa(Register, Offset); |
1467 | 2.42k | OS << "\t.cfi_def_cfa "; |
1468 | 2.42k | EmitRegisterName(Register); |
1469 | 2.42k | OS << ", " << Offset; |
1470 | 2.42k | EmitEOL(); |
1471 | 2.42k | } |
1472 | | |
1473 | 17.1k | void MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { |
1474 | 17.1k | MCStreamer::EmitCFIDefCfaOffset(Offset); |
1475 | 17.1k | OS << "\t.cfi_def_cfa_offset " << Offset; |
1476 | 17.1k | EmitEOL(); |
1477 | 17.1k | } |
1478 | | |
1479 | 33 | static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) { |
1480 | 33 | OS << "\t.cfi_escape "; |
1481 | 33 | if (!Values.empty()) { |
1482 | 33 | size_t e = Values.size() - 1; |
1483 | 72 | for (size_t i = 0; i < e; ++i39 ) |
1484 | 39 | OS << format("0x%02x", uint8_t(Values[i])) << ", "; |
1485 | 33 | OS << format("0x%02x", uint8_t(Values[e])); |
1486 | 33 | } |
1487 | 33 | } |
1488 | | |
1489 | 2 | void MCAsmStreamer::EmitCFIEscape(StringRef Values) { |
1490 | 2 | MCStreamer::EmitCFIEscape(Values); |
1491 | 2 | PrintCFIEscape(OS, Values); |
1492 | 2 | EmitEOL(); |
1493 | 2 | } |
1494 | | |
1495 | 31 | void MCAsmStreamer::EmitCFIGnuArgsSize(int64_t Size) { |
1496 | 31 | MCStreamer::EmitCFIGnuArgsSize(Size); |
1497 | 31 | |
1498 | 31 | uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size }; |
1499 | 31 | unsigned Len = encodeULEB128(Size, Buffer + 1) + 1; |
1500 | 31 | |
1501 | 31 | PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len)); |
1502 | 31 | EmitEOL(); |
1503 | 31 | } |
1504 | | |
1505 | 1.58k | void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { |
1506 | 1.58k | MCStreamer::EmitCFIDefCfaRegister(Register); |
1507 | 1.58k | OS << "\t.cfi_def_cfa_register "; |
1508 | 1.58k | EmitRegisterName(Register); |
1509 | 1.58k | EmitEOL(); |
1510 | 1.58k | } |
1511 | | |
1512 | 21.7k | void MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { |
1513 | 21.7k | this->MCStreamer::EmitCFIOffset(Register, Offset); |
1514 | 21.7k | OS << "\t.cfi_offset "; |
1515 | 21.7k | EmitRegisterName(Register); |
1516 | 21.7k | OS << ", " << Offset; |
1517 | 21.7k | EmitEOL(); |
1518 | 21.7k | } |
1519 | | |
1520 | | void MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, |
1521 | 225 | unsigned Encoding) { |
1522 | 225 | MCStreamer::EmitCFIPersonality(Sym, Encoding); |
1523 | 225 | OS << "\t.cfi_personality " << Encoding << ", "; |
1524 | 225 | Sym->print(OS, MAI); |
1525 | 225 | EmitEOL(); |
1526 | 225 | } |
1527 | | |
1528 | 225 | void MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { |
1529 | 225 | MCStreamer::EmitCFILsda(Sym, Encoding); |
1530 | 225 | OS << "\t.cfi_lsda " << Encoding << ", "; |
1531 | 225 | Sym->print(OS, MAI); |
1532 | 225 | EmitEOL(); |
1533 | 225 | } |
1534 | | |
1535 | 0 | void MCAsmStreamer::EmitCFIRememberState() { |
1536 | 0 | MCStreamer::EmitCFIRememberState(); |
1537 | 0 | OS << "\t.cfi_remember_state"; |
1538 | 0 | EmitEOL(); |
1539 | 0 | } |
1540 | | |
1541 | 0 | void MCAsmStreamer::EmitCFIRestoreState() { |
1542 | 0 | MCStreamer::EmitCFIRestoreState(); |
1543 | 0 | OS << "\t.cfi_restore_state"; |
1544 | 0 | EmitEOL(); |
1545 | 0 | } |
1546 | | |
1547 | 69 | void MCAsmStreamer::EmitCFIRestore(int64_t Register) { |
1548 | 69 | MCStreamer::EmitCFIRestore(Register); |
1549 | 69 | OS << "\t.cfi_restore "; |
1550 | 69 | EmitRegisterName(Register); |
1551 | 69 | EmitEOL(); |
1552 | 69 | } |
1553 | | |
1554 | 2 | void MCAsmStreamer::EmitCFISameValue(int64_t Register) { |
1555 | 2 | MCStreamer::EmitCFISameValue(Register); |
1556 | 2 | OS << "\t.cfi_same_value "; |
1557 | 2 | EmitRegisterName(Register); |
1558 | 2 | EmitEOL(); |
1559 | 2 | } |
1560 | | |
1561 | 1 | void MCAsmStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { |
1562 | 1 | MCStreamer::EmitCFIRelOffset(Register, Offset); |
1563 | 1 | OS << "\t.cfi_rel_offset "; |
1564 | 1 | EmitRegisterName(Register); |
1565 | 1 | OS << ", " << Offset; |
1566 | 1 | EmitEOL(); |
1567 | 1 | } |
1568 | | |
1569 | 1.97k | void MCAsmStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { |
1570 | 1.97k | MCStreamer::EmitCFIAdjustCfaOffset(Adjustment); |
1571 | 1.97k | OS << "\t.cfi_adjust_cfa_offset " << Adjustment; |
1572 | 1.97k | EmitEOL(); |
1573 | 1.97k | } |
1574 | | |
1575 | 0 | void MCAsmStreamer::EmitCFISignalFrame() { |
1576 | 0 | MCStreamer::EmitCFISignalFrame(); |
1577 | 0 | OS << "\t.cfi_signal_frame"; |
1578 | 0 | EmitEOL(); |
1579 | 0 | } |
1580 | | |
1581 | 0 | void MCAsmStreamer::EmitCFIUndefined(int64_t Register) { |
1582 | 0 | MCStreamer::EmitCFIUndefined(Register); |
1583 | 0 | OS << "\t.cfi_undefined " << Register; |
1584 | 0 | EmitEOL(); |
1585 | 0 | } |
1586 | | |
1587 | 366 | void MCAsmStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { |
1588 | 366 | MCStreamer::EmitCFIRegister(Register1, Register2); |
1589 | 366 | OS << "\t.cfi_register " << Register1 << ", " << Register2; |
1590 | 366 | EmitEOL(); |
1591 | 366 | } |
1592 | | |
1593 | 364 | void MCAsmStreamer::EmitCFIWindowSave() { |
1594 | 364 | MCStreamer::EmitCFIWindowSave(); |
1595 | 364 | OS << "\t.cfi_window_save"; |
1596 | 364 | EmitEOL(); |
1597 | 364 | } |
1598 | | |
1599 | 9 | void MCAsmStreamer::EmitCFINegateRAState() { |
1600 | 9 | MCStreamer::EmitCFINegateRAState(); |
1601 | 9 | OS << "\t.cfi_negate_ra_state"; |
1602 | 9 | EmitEOL(); |
1603 | 9 | } |
1604 | | |
1605 | 3 | void MCAsmStreamer::EmitCFIReturnColumn(int64_t Register) { |
1606 | 3 | MCStreamer::EmitCFIReturnColumn(Register); |
1607 | 3 | OS << "\t.cfi_return_column " << Register; |
1608 | 3 | EmitEOL(); |
1609 | 3 | } |
1610 | | |
1611 | 2 | void MCAsmStreamer::EmitCFIBKeyFrame() { |
1612 | 2 | MCStreamer::EmitCFIBKeyFrame(); |
1613 | 2 | OS << "\t.cfi_b_key_frame"; |
1614 | 2 | EmitEOL(); |
1615 | 2 | } |
1616 | | |
1617 | 686 | void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { |
1618 | 686 | MCStreamer::EmitWinCFIStartProc(Symbol, Loc); |
1619 | 686 | |
1620 | 686 | OS << ".seh_proc "; |
1621 | 686 | Symbol->print(OS, MAI); |
1622 | 686 | EmitEOL(); |
1623 | 686 | } |
1624 | | |
1625 | 685 | void MCAsmStreamer::EmitWinCFIEndProc(SMLoc Loc) { |
1626 | 685 | MCStreamer::EmitWinCFIEndProc(Loc); |
1627 | 685 | |
1628 | 685 | OS << "\t.seh_endproc"; |
1629 | 685 | EmitEOL(); |
1630 | 685 | } |
1631 | | |
1632 | | // TODO: Implement |
1633 | 141 | void MCAsmStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) { |
1634 | 141 | } |
1635 | | |
1636 | 1 | void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) { |
1637 | 1 | MCStreamer::EmitWinCFIStartChained(Loc); |
1638 | 1 | |
1639 | 1 | OS << "\t.seh_startchained"; |
1640 | 1 | EmitEOL(); |
1641 | 1 | } |
1642 | | |
1643 | 1 | void MCAsmStreamer::EmitWinCFIEndChained(SMLoc Loc) { |
1644 | 1 | MCStreamer::EmitWinCFIEndChained(Loc); |
1645 | 1 | |
1646 | 1 | OS << "\t.seh_endchained"; |
1647 | 1 | EmitEOL(); |
1648 | 1 | } |
1649 | | |
1650 | | void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, |
1651 | 153 | bool Except, SMLoc Loc) { |
1652 | 153 | MCStreamer::EmitWinEHHandler(Sym, Unwind, Except, Loc); |
1653 | 153 | |
1654 | 153 | OS << "\t.seh_handler "; |
1655 | 153 | Sym->print(OS, MAI); |
1656 | 153 | if (Unwind) |
1657 | 152 | OS << ", @unwind"; |
1658 | 153 | if (Except) |
1659 | 153 | OS << ", @except"; |
1660 | 153 | EmitEOL(); |
1661 | 153 | } |
1662 | | |
1663 | 685 | void MCAsmStreamer::EmitWinEHHandlerData(SMLoc Loc) { |
1664 | 685 | MCStreamer::EmitWinEHHandlerData(Loc); |
1665 | 685 | |
1666 | 685 | // Switch sections. Don't call SwitchSection directly, because that will |
1667 | 685 | // cause the section switch to be visible in the emitted assembly. |
1668 | 685 | // We only do this so the section switch that terminates the handler |
1669 | 685 | // data block is visible. |
1670 | 685 | WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo(); |
1671 | 685 | MCSection *TextSec = &CurFrame->Function->getSection(); |
1672 | 685 | MCSection *XData = getAssociatedXDataSection(TextSec); |
1673 | 685 | SwitchSectionNoChange(XData); |
1674 | 685 | |
1675 | 685 | OS << "\t.seh_handlerdata"; |
1676 | 685 | EmitEOL(); |
1677 | 685 | } |
1678 | | |
1679 | 425 | void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { |
1680 | 425 | MCStreamer::EmitWinCFIPushReg(Register, Loc); |
1681 | 425 | |
1682 | 425 | OS << "\t.seh_pushreg " << Register; |
1683 | 425 | EmitEOL(); |
1684 | 425 | } |
1685 | | |
1686 | | void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, |
1687 | 94 | SMLoc Loc) { |
1688 | 94 | MCStreamer::EmitWinCFISetFrame(Register, Offset, Loc); |
1689 | 94 | |
1690 | 94 | OS << "\t.seh_setframe " << Register << ", " << Offset; |
1691 | 94 | EmitEOL(); |
1692 | 94 | } |
1693 | | |
1694 | 517 | void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { |
1695 | 517 | MCStreamer::EmitWinCFIAllocStack(Size, Loc); |
1696 | 517 | |
1697 | 517 | OS << "\t.seh_stackalloc " << Size; |
1698 | 517 | EmitEOL(); |
1699 | 517 | } |
1700 | | |
1701 | | void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, |
1702 | 1 | SMLoc Loc) { |
1703 | 1 | MCStreamer::EmitWinCFISaveReg(Register, Offset, Loc); |
1704 | 1 | |
1705 | 1 | OS << "\t.seh_savereg " << Register << ", " << Offset; |
1706 | 1 | EmitEOL(); |
1707 | 1 | } |
1708 | | |
1709 | | void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, |
1710 | 191 | SMLoc Loc) { |
1711 | 191 | MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc); |
1712 | 191 | |
1713 | 191 | OS << "\t.seh_savexmm " << Register << ", " << Offset; |
1714 | 191 | EmitEOL(); |
1715 | 191 | } |
1716 | | |
1717 | 1 | void MCAsmStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) { |
1718 | 1 | MCStreamer::EmitWinCFIPushFrame(Code, Loc); |
1719 | 1 | |
1720 | 1 | OS << "\t.seh_pushframe"; |
1721 | 1 | if (Code) |
1722 | 1 | OS << " @code"; |
1723 | 1 | EmitEOL(); |
1724 | 1 | } |
1725 | | |
1726 | 545 | void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) { |
1727 | 545 | MCStreamer::EmitWinCFIEndProlog(Loc); |
1728 | 545 | |
1729 | 545 | OS << "\t.seh_endprologue"; |
1730 | 545 | EmitEOL(); |
1731 | 545 | } |
1732 | | |
1733 | | void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, |
1734 | | const MCSymbolRefExpr *To, |
1735 | 6 | uint64_t Count) { |
1736 | 6 | OS << "\t.cg_profile "; |
1737 | 6 | From->getSymbol().print(OS, MAI); |
1738 | 6 | OS << ", "; |
1739 | 6 | To->getSymbol().print(OS, MAI); |
1740 | 6 | OS << ", " << Count; |
1741 | 6 | EmitEOL(); |
1742 | 6 | } |
1743 | | |
1744 | | void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, |
1745 | 2.67M | const MCSubtargetInfo &STI) { |
1746 | 2.67M | raw_ostream &OS = GetCommentOS(); |
1747 | 2.67M | SmallString<256> Code; |
1748 | 2.67M | SmallVector<MCFixup, 4> Fixups; |
1749 | 2.67M | raw_svector_ostream VecOS(Code); |
1750 | 2.67M | |
1751 | 2.67M | // If we have no code emitter, don't emit code. |
1752 | 2.67M | if (!getAssembler().getEmitterPtr()) |
1753 | 1.99M | return; |
1754 | 676k | |
1755 | 676k | getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); |
1756 | 676k | |
1757 | 676k | // If we are showing fixups, create symbolic markers in the encoded |
1758 | 676k | // representation. We do this by making a per-bit map to the fixup item index, |
1759 | 676k | // then trying to display it as nicely as possible. |
1760 | 676k | SmallVector<uint8_t, 64> FixupMap; |
1761 | 676k | FixupMap.resize(Code.size() * 8); |
1762 | 35.5M | for (unsigned i = 0, e = Code.size() * 8; i != e; ++i34.8M ) |
1763 | 34.8M | FixupMap[i] = 0; |
1764 | 676k | |
1765 | 682k | for (unsigned i = 0, e = Fixups.size(); i != e; ++i6.02k ) { |
1766 | 6.02k | MCFixup &F = Fixups[i]; |
1767 | 6.02k | const MCFixupKindInfo &Info = |
1768 | 6.02k | getAssembler().getBackend().getFixupKindInfo(F.getKind()); |
1769 | 119k | for (unsigned j = 0; j != Info.TargetSize; ++j113k ) { |
1770 | 113k | unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; |
1771 | 113k | assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); |
1772 | 113k | FixupMap[Index] = 1 + i; |
1773 | 113k | } |
1774 | 6.02k | } |
1775 | 676k | |
1776 | 676k | // FIXME: Note the fixup comments for Thumb2 are completely bogus since the |
1777 | 676k | // high order halfword of a 32-bit Thumb2 instruction is emitted first. |
1778 | 676k | OS << "encoding: ["; |
1779 | 5.03M | for (unsigned i = 0, e = Code.size(); i != e; ++i4.35M ) { |
1780 | 4.35M | if (i) |
1781 | 3.68M | OS << ','; |
1782 | 4.35M | |
1783 | 4.35M | // See if all bits are the same map entry. |
1784 | 4.35M | uint8_t MapEntry = FixupMap[i * 8 + 0]; |
1785 | 34.8M | for (unsigned j = 1; j != 8; ++j30.5M ) { |
1786 | 30.5M | if (FixupMap[i * 8 + j] == MapEntry) |
1787 | 30.5M | continue; |
1788 | 2.31k | |
1789 | 2.31k | MapEntry = uint8_t(~0U); |
1790 | 2.31k | break; |
1791 | 2.31k | } |
1792 | 4.35M | |
1793 | 4.35M | if (MapEntry != uint8_t(~0U)) { |
1794 | 4.35M | if (MapEntry == 0) { |
1795 | 4.34M | OS << format("0x%02x", uint8_t(Code[i])); |
1796 | 4.34M | } else { |
1797 | 12.6k | if (Code[i]) { |
1798 | 681 | // FIXME: Some of the 8 bits require fix up. |
1799 | 681 | OS << format("0x%02x", uint8_t(Code[i])) << '\'' |
1800 | 681 | << char('A' + MapEntry - 1) << '\''; |
1801 | 681 | } else |
1802 | 11.9k | OS << char('A' + MapEntry - 1); |
1803 | 12.6k | } |
1804 | 4.35M | } else { |
1805 | 2.31k | // Otherwise, write out in binary. |
1806 | 2.31k | OS << "0b"; |
1807 | 20.8k | for (unsigned j = 8; j--;) { |
1808 | 18.5k | unsigned Bit = (Code[i] >> j) & 1; |
1809 | 18.5k | |
1810 | 18.5k | unsigned FixupBit; |
1811 | 18.5k | if (MAI->isLittleEndian()) |
1812 | 9.83k | FixupBit = i * 8 + j; |
1813 | 8.70k | else |
1814 | 8.70k | FixupBit = i * 8 + (7-j); |
1815 | 18.5k | |
1816 | 18.5k | if (uint8_t MapEntry = FixupMap[FixupBit]) { |
1817 | 11.6k | assert(Bit == 0 && "Encoder wrote into fixed up bit!"); |
1818 | 11.6k | OS << char('A' + MapEntry - 1); |
1819 | 11.6k | } else |
1820 | 6.85k | OS << Bit; |
1821 | 18.5k | } |
1822 | 2.31k | } |
1823 | 4.35M | } |
1824 | 676k | OS << "]\n"; |
1825 | 676k | |
1826 | 682k | for (unsigned i = 0, e = Fixups.size(); i != e; ++i6.02k ) { |
1827 | 6.02k | MCFixup &F = Fixups[i]; |
1828 | 6.02k | const MCFixupKindInfo &Info = |
1829 | 6.02k | getAssembler().getBackend().getFixupKindInfo(F.getKind()); |
1830 | 6.02k | OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() |
1831 | 6.02k | << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; |
1832 | 6.02k | } |
1833 | 676k | } |
1834 | | |
1835 | | void MCAsmStreamer::EmitInstruction(const MCInst &Inst, |
1836 | 2.67M | const MCSubtargetInfo &STI) { |
1837 | 2.67M | assert(getCurrentSectionOnly() && |
1838 | 2.67M | "Cannot emit contents before setting section!"); |
1839 | 2.67M | |
1840 | 2.67M | // Show the encoding in a comment if we have a code emitter. |
1841 | 2.67M | AddEncodingComment(Inst, STI); |
1842 | 2.67M | |
1843 | 2.67M | // Show the MCInst if enabled. |
1844 | 2.67M | if (ShowInst) { |
1845 | 8.73k | Inst.dump_pretty(GetCommentOS(), InstPrinter.get(), "\n "); |
1846 | 8.73k | GetCommentOS() << "\n"; |
1847 | 8.73k | } |
1848 | 2.67M | |
1849 | 2.67M | if(getTargetStreamer()) |
1850 | 2.49M | getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI); |
1851 | 178k | else |
1852 | 178k | InstPrinter->printInst(&Inst, OS, "", STI); |
1853 | 2.67M | |
1854 | 2.67M | StringRef Comments = CommentToEmit; |
1855 | 2.67M | if (Comments.size() && Comments.back() != '\n'833k ) |
1856 | 12.4k | GetCommentOS() << "\n"; |
1857 | 2.67M | |
1858 | 2.67M | EmitEOL(); |
1859 | 2.67M | } |
1860 | | |
1861 | 1 | void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) { |
1862 | 1 | OS << "\t.bundle_align_mode " << AlignPow2; |
1863 | 1 | EmitEOL(); |
1864 | 1 | } |
1865 | | |
1866 | 4 | void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) { |
1867 | 4 | OS << "\t.bundle_lock"; |
1868 | 4 | if (AlignToEnd) |
1869 | 3 | OS << " align_to_end"; |
1870 | 4 | EmitEOL(); |
1871 | 4 | } |
1872 | | |
1873 | 2 | void MCAsmStreamer::EmitBundleUnlock() { |
1874 | 2 | OS << "\t.bundle_unlock"; |
1875 | 2 | EmitEOL(); |
1876 | 2 | } |
1877 | | |
1878 | | bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, |
1879 | | const MCExpr *Expr, SMLoc, |
1880 | 1.11k | const MCSubtargetInfo &STI) { |
1881 | 1.11k | OS << "\t.reloc "; |
1882 | 1.11k | Offset.print(OS, MAI); |
1883 | 1.11k | OS << ", " << Name; |
1884 | 1.11k | if (Expr) { |
1885 | 1.11k | OS << ", "; |
1886 | 1.11k | Expr->print(OS, MAI); |
1887 | 1.11k | } |
1888 | 1.11k | EmitEOL(); |
1889 | 1.11k | return false; |
1890 | 1.11k | } |
1891 | | |
1892 | 40 | void MCAsmStreamer::EmitAddrsig() { |
1893 | 40 | OS << "\t.addrsig"; |
1894 | 40 | EmitEOL(); |
1895 | 40 | } |
1896 | | |
1897 | 10 | void MCAsmStreamer::EmitAddrsigSym(const MCSymbol *Sym) { |
1898 | 10 | OS << "\t.addrsig_sym "; |
1899 | 10 | Sym->print(OS, MAI); |
1900 | 10 | EmitEOL(); |
1901 | 10 | } |
1902 | | |
1903 | | /// EmitRawText - If this file is backed by an assembly streamer, this dumps |
1904 | | /// the specified string in the output .s file. This capability is |
1905 | | /// indicated by the hasRawTextSupport() predicate. |
1906 | 660k | void MCAsmStreamer::EmitRawTextImpl(StringRef String) { |
1907 | 660k | if (!String.empty() && String.back() == '\n'658k ) |
1908 | 9.36k | String = String.substr(0, String.size()-1); |
1909 | 660k | OS << String; |
1910 | 660k | EmitEOL(); |
1911 | 660k | } |
1912 | | |
1913 | 23.5k | void MCAsmStreamer::FinishImpl() { |
1914 | 23.5k | // If we are generating dwarf for assembly source files dump out the sections. |
1915 | 23.5k | if (getContext().getGenDwarfForAssembly()) |
1916 | 10 | MCGenDwarfInfo::Emit(this); |
1917 | 23.5k | |
1918 | 23.5k | // Emit the label for the line table, if requested - since the rest of the |
1919 | 23.5k | // line table will be defined by .loc/.file directives, and not emitted |
1920 | 23.5k | // directly, the label is the only work required here. |
1921 | 23.5k | const auto &Tables = getContext().getMCDwarfLineTables(); |
1922 | 23.5k | if (!Tables.empty()) { |
1923 | 466 | assert(Tables.size() == 1 && "asm output only supports one line table"); |
1924 | 466 | if (auto *Label = Tables.begin()->second.getLabel()) { |
1925 | 448 | SwitchSection(getContext().getObjectFileInfo()->getDwarfLineSection()); |
1926 | 448 | EmitLabel(Label); |
1927 | 448 | } |
1928 | 466 | } |
1929 | 23.5k | } |
1930 | | |
1931 | | MCStreamer *llvm::createAsmStreamer(MCContext &Context, |
1932 | | std::unique_ptr<formatted_raw_ostream> OS, |
1933 | | bool isVerboseAsm, bool useDwarfDirectory, |
1934 | | MCInstPrinter *IP, |
1935 | | std::unique_ptr<MCCodeEmitter> &&CE, |
1936 | | std::unique_ptr<MCAsmBackend> &&MAB, |
1937 | 26.7k | bool ShowInst) { |
1938 | 26.7k | return new MCAsmStreamer(Context, std::move(OS), isVerboseAsm, |
1939 | 26.7k | useDwarfDirectory, IP, std::move(CE), std::move(MAB), |
1940 | 26.7k | ShowInst); |
1941 | 26.7k | } |