]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output --------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | ||
10 | #include "llvm/MC/MCStreamer.h" | |
1a4d82fc | 11 | #include "llvm/ADT/STLExtras.h" |
85aaf69f | 12 | #include "llvm/ADT/SmallString.h" |
970d7e83 LB |
13 | #include "llvm/ADT/StringExtras.h" |
14 | #include "llvm/ADT/Twine.h" | |
15 | #include "llvm/MC/MCAsmBackend.h" | |
223e47cc LB |
16 | #include "llvm/MC/MCAsmInfo.h" |
17 | #include "llvm/MC/MCCodeEmitter.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/MCRegisterInfo.h" | |
25 | #include "llvm/MC/MCSectionCOFF.h" | |
26 | #include "llvm/MC/MCSectionMachO.h" | |
27 | #include "llvm/MC/MCSymbol.h" | |
1a4d82fc | 28 | #include "llvm/Support/CommandLine.h" |
223e47cc | 29 | #include "llvm/Support/ErrorHandling.h" |
223e47cc LB |
30 | #include "llvm/Support/Format.h" |
31 | #include "llvm/Support/FormattedStream.h" | |
970d7e83 | 32 | #include "llvm/Support/MathExtras.h" |
1a4d82fc | 33 | #include "llvm/Support/Path.h" |
223e47cc LB |
34 | #include <cctype> |
35 | using namespace llvm; | |
36 | ||
37 | namespace { | |
38 | ||
39 | class MCAsmStreamer : public MCStreamer { | |
40 | protected: | |
41 | formatted_raw_ostream &OS; | |
1a4d82fc | 42 | const MCAsmInfo *MAI; |
223e47cc | 43 | private: |
1a4d82fc JJ |
44 | std::unique_ptr<MCInstPrinter> InstPrinter; |
45 | std::unique_ptr<MCCodeEmitter> Emitter; | |
46 | std::unique_ptr<MCAsmBackend> AsmBackend; | |
223e47cc LB |
47 | |
48 | SmallString<128> CommentToEmit; | |
49 | raw_svector_ostream CommentStream; | |
50 | ||
51 | unsigned IsVerboseAsm : 1; | |
52 | unsigned ShowInst : 1; | |
223e47cc LB |
53 | unsigned UseDwarfDirectory : 1; |
54 | ||
223e47cc | 55 | void EmitRegisterName(int64_t Register); |
1a4d82fc JJ |
56 | void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override; |
57 | void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override; | |
223e47cc LB |
58 | |
59 | public: | |
60 | MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, | |
1a4d82fc | 61 | bool isVerboseAsm, bool useDwarfDirectory, |
223e47cc | 62 | MCInstPrinter *printer, MCCodeEmitter *emitter, |
1a4d82fc JJ |
63 | MCAsmBackend *asmbackend, bool showInst) |
64 | : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()), | |
65 | InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend), | |
66 | CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), | |
67 | ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) { | |
223e47cc LB |
68 | if (InstPrinter && IsVerboseAsm) |
69 | InstPrinter->setCommentStream(CommentStream); | |
70 | } | |
223e47cc LB |
71 | |
72 | inline void EmitEOL() { | |
73 | // If we don't have any comments, just emit a \n. | |
74 | if (!IsVerboseAsm) { | |
75 | OS << '\n'; | |
76 | return; | |
77 | } | |
78 | EmitCommentsAndEOL(); | |
79 | } | |
80 | void EmitCommentsAndEOL(); | |
81 | ||
82 | /// isVerboseAsm - Return true if this streamer supports verbose assembly at | |
83 | /// all. | |
1a4d82fc | 84 | bool isVerboseAsm() const override { return IsVerboseAsm; } |
223e47cc LB |
85 | |
86 | /// hasRawTextSupport - We support EmitRawText. | |
1a4d82fc | 87 | bool hasRawTextSupport() const override { return true; } |
223e47cc LB |
88 | |
89 | /// AddComment - Add a comment that can be emitted to the generated .s | |
90 | /// file if applicable as a QoI issue to make the output of the compiler | |
91 | /// more readable. This only affects the MCAsmStreamer, and only when | |
92 | /// verbose assembly output is enabled. | |
1a4d82fc | 93 | void AddComment(const Twine &T) override; |
223e47cc LB |
94 | |
95 | /// AddEncodingComment - Add a comment showing the encoding of an instruction. | |
1a4d82fc | 96 | void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &); |
223e47cc LB |
97 | |
98 | /// GetCommentOS - Return a raw_ostream that comments can be written to. | |
99 | /// Unlike AddComment, you are required to terminate comments with \n if you | |
100 | /// use this method. | |
1a4d82fc | 101 | raw_ostream &GetCommentOS() override { |
223e47cc LB |
102 | if (!IsVerboseAsm) |
103 | return nulls(); // Discard comments unless in verbose asm mode. | |
104 | return CommentStream; | |
105 | } | |
106 | ||
1a4d82fc JJ |
107 | void emitRawComment(const Twine &T, bool TabPrefix = true) override; |
108 | ||
223e47cc | 109 | /// AddBlankLine - Emit a blank line to a .s file to pretty it up. |
1a4d82fc | 110 | void AddBlankLine() override { |
223e47cc LB |
111 | EmitEOL(); |
112 | } | |
113 | ||
114 | /// @name MCStreamer Interface | |
115 | /// @{ | |
116 | ||
1a4d82fc JJ |
117 | void ChangeSection(const MCSection *Section, |
118 | const MCExpr *Subsection) override; | |
119 | ||
120 | void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override; | |
121 | void EmitLabel(MCSymbol *Symbol) override; | |
122 | ||
123 | void EmitAssemblerFlag(MCAssemblerFlag Flag) override; | |
124 | void EmitLinkerOptions(ArrayRef<std::string> Options) override; | |
125 | void EmitDataRegion(MCDataRegionType Kind) override; | |
126 | void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, | |
127 | unsigned Update) override; | |
128 | void EmitThumbFunc(MCSymbol *Func) override; | |
129 | ||
130 | void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; | |
131 | void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; | |
132 | bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; | |
133 | ||
134 | void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; | |
135 | void BeginCOFFSymbolDef(const MCSymbol *Symbol) override; | |
136 | void EmitCOFFSymbolStorageClass(int StorageClass) override; | |
137 | void EmitCOFFSymbolType(int Type) override; | |
138 | void EndCOFFSymbolDef() override; | |
139 | void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; | |
140 | void EmitCOFFSecRel32(MCSymbol const *Symbol) override; | |
141 | void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; | |
142 | void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, | |
143 | unsigned ByteAlignment) override; | |
223e47cc LB |
144 | |
145 | /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. | |
146 | /// | |
147 | /// @param Symbol - The common symbol to emit. | |
148 | /// @param Size - The size of the common symbol. | |
149 | /// @param ByteAlignment - The alignment of the common symbol in bytes. | |
1a4d82fc JJ |
150 | void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
151 | unsigned ByteAlignment) override; | |
152 | ||
153 | void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = nullptr, | |
154 | uint64_t Size = 0, unsigned ByteAlignment = 0) override; | |
155 | ||
156 | void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol, | |
157 | uint64_t Size, unsigned ByteAlignment = 0) override; | |
158 | ||
159 | void EmitBytes(StringRef Data) override; | |
160 | ||
161 | void EmitValueImpl(const MCExpr *Value, unsigned Size, | |
162 | const SMLoc &Loc = SMLoc()) override; | |
163 | void EmitIntValue(uint64_t Value, unsigned Size) override; | |
164 | ||
165 | void EmitULEB128Value(const MCExpr *Value) override; | |
166 | ||
167 | void EmitSLEB128Value(const MCExpr *Value) override; | |
168 | ||
169 | void EmitGPRel64Value(const MCExpr *Value) override; | |
170 | ||
171 | void EmitGPRel32Value(const MCExpr *Value) override; | |
172 | ||
173 | ||
174 | void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; | |
175 | ||
176 | void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, | |
177 | unsigned ValueSize = 1, | |
178 | unsigned MaxBytesToEmit = 0) override; | |
179 | ||
180 | void EmitCodeAlignment(unsigned ByteAlignment, | |
181 | unsigned MaxBytesToEmit = 0) override; | |
182 | ||
183 | bool EmitValueToOffset(const MCExpr *Offset, | |
184 | unsigned char Value = 0) override; | |
185 | ||
186 | void EmitFileDirective(StringRef Filename) override; | |
187 | unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, | |
188 | StringRef Filename, | |
189 | unsigned CUID = 0) override; | |
190 | void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, | |
191 | unsigned Column, unsigned Flags, | |
192 | unsigned Isa, unsigned Discriminator, | |
193 | StringRef FileName) override; | |
194 | MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override; | |
195 | ||
196 | void EmitIdent(StringRef IdentString) override; | |
197 | void EmitCFISections(bool EH, bool Debug) override; | |
198 | void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; | |
199 | void EmitCFIDefCfaOffset(int64_t Offset) override; | |
200 | void EmitCFIDefCfaRegister(int64_t Register) override; | |
201 | void EmitCFIOffset(int64_t Register, int64_t Offset) override; | |
202 | void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override; | |
203 | void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) override; | |
204 | void EmitCFIRememberState() override; | |
205 | void EmitCFIRestoreState() override; | |
206 | void EmitCFISameValue(int64_t Register) override; | |
207 | void EmitCFIRelOffset(int64_t Register, int64_t Offset) override; | |
208 | void EmitCFIAdjustCfaOffset(int64_t Adjustment) override; | |
209 | void EmitCFISignalFrame() override; | |
210 | void EmitCFIUndefined(int64_t Register) override; | |
211 | void EmitCFIRegister(int64_t Register1, int64_t Register2) override; | |
212 | void EmitCFIWindowSave() override; | |
213 | ||
214 | void EmitWinCFIStartProc(const MCSymbol *Symbol) override; | |
215 | void EmitWinCFIEndProc() override; | |
216 | void EmitWinCFIStartChained() override; | |
217 | void EmitWinCFIEndChained() override; | |
218 | void EmitWinCFIPushReg(unsigned Register) override; | |
219 | void EmitWinCFISetFrame(unsigned Register, unsigned Offset) override; | |
220 | void EmitWinCFIAllocStack(unsigned Size) override; | |
221 | void EmitWinCFISaveReg(unsigned Register, unsigned Offset) override; | |
222 | void EmitWinCFISaveXMM(unsigned Register, unsigned Offset) override; | |
223 | void EmitWinCFIPushFrame(bool Code) override; | |
224 | void EmitWinCFIEndProlog() override; | |
225 | ||
226 | void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except) override; | |
227 | void EmitWinEHHandlerData() override; | |
228 | ||
229 | void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; | |
230 | ||
231 | void EmitBundleAlignMode(unsigned AlignPow2) override; | |
232 | void EmitBundleLock(bool AlignToEnd) override; | |
233 | void EmitBundleUnlock() override; | |
970d7e83 | 234 | |
223e47cc LB |
235 | /// EmitRawText - If this file is backed by an assembly streamer, this dumps |
236 | /// the specified string in the output .s file. This capability is | |
237 | /// indicated by the hasRawTextSupport() predicate. | |
1a4d82fc | 238 | void EmitRawTextImpl(StringRef String) override; |
223e47cc | 239 | |
1a4d82fc | 240 | void FinishImpl() override; |
223e47cc LB |
241 | }; |
242 | ||
243 | } // end anonymous namespace. | |
244 | ||
245 | /// AddComment - Add a comment that can be emitted to the generated .s | |
246 | /// file if applicable as a QoI issue to make the output of the compiler | |
247 | /// more readable. This only affects the MCAsmStreamer, and only when | |
248 | /// verbose assembly output is enabled. | |
249 | void MCAsmStreamer::AddComment(const Twine &T) { | |
250 | if (!IsVerboseAsm) return; | |
251 | ||
252 | // Make sure that CommentStream is flushed. | |
253 | CommentStream.flush(); | |
254 | ||
255 | T.toVector(CommentToEmit); | |
256 | // Each comment goes on its own line. | |
257 | CommentToEmit.push_back('\n'); | |
258 | ||
259 | // Tell the comment stream that the vector changed underneath it. | |
260 | CommentStream.resync(); | |
261 | } | |
262 | ||
263 | void MCAsmStreamer::EmitCommentsAndEOL() { | |
264 | if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) { | |
265 | OS << '\n'; | |
266 | return; | |
267 | } | |
268 | ||
269 | CommentStream.flush(); | |
270 | StringRef Comments = CommentToEmit.str(); | |
271 | ||
272 | assert(Comments.back() == '\n' && | |
273 | "Comment array not newline terminated"); | |
274 | do { | |
275 | // Emit a line of comments. | |
1a4d82fc | 276 | OS.PadToColumn(MAI->getCommentColumn()); |
223e47cc | 277 | size_t Position = Comments.find('\n'); |
1a4d82fc | 278 | OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n'; |
223e47cc LB |
279 | |
280 | Comments = Comments.substr(Position+1); | |
281 | } while (!Comments.empty()); | |
282 | ||
283 | CommentToEmit.clear(); | |
284 | // Tell the comment stream that the vector changed underneath it. | |
285 | CommentStream.resync(); | |
286 | } | |
287 | ||
288 | static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { | |
289 | assert(Bytes && "Invalid size!"); | |
290 | return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); | |
291 | } | |
292 | ||
1a4d82fc JJ |
293 | void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) { |
294 | if (TabPrefix) | |
295 | OS << '\t'; | |
296 | OS << MAI->getCommentString() << T; | |
297 | EmitEOL(); | |
223e47cc LB |
298 | } |
299 | ||
1a4d82fc JJ |
300 | void MCAsmStreamer::ChangeSection(const MCSection *Section, |
301 | const MCExpr *Subsection) { | |
302 | assert(Section && "Cannot switch to a null section!"); | |
303 | Section->PrintSwitchToSection(*MAI, OS, Subsection); | |
223e47cc LB |
304 | } |
305 | ||
306 | void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { | |
307 | assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); | |
308 | MCStreamer::EmitLabel(Symbol); | |
309 | ||
1a4d82fc | 310 | OS << *Symbol << MAI->getLabelSuffix(); |
223e47cc LB |
311 | EmitEOL(); |
312 | } | |
313 | ||
1a4d82fc JJ |
314 | void MCAsmStreamer::EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) { |
315 | StringRef str = MCLOHIdToName(Kind); | |
316 | ||
317 | #ifndef NDEBUG | |
318 | int NbArgs = MCLOHIdToNbArgs(Kind); | |
319 | assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!"); | |
320 | assert(str != "" && "Invalid LOH name"); | |
321 | #endif | |
970d7e83 | 322 | |
1a4d82fc JJ |
323 | OS << "\t" << MCLOHDirectiveName() << " " << str << "\t"; |
324 | bool IsFirst = true; | |
325 | for (MCLOHArgs::const_iterator It = Args.begin(), EndIt = Args.end(); | |
326 | It != EndIt; ++It) { | |
327 | if (!IsFirst) | |
328 | OS << ", "; | |
329 | IsFirst = false; | |
330 | OS << **It; | |
331 | } | |
970d7e83 LB |
332 | EmitEOL(); |
333 | } | |
334 | ||
223e47cc LB |
335 | void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { |
336 | switch (Flag) { | |
337 | case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; | |
338 | case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; | |
1a4d82fc JJ |
339 | case MCAF_Code16: OS << '\t'<< MAI->getCode16Directive();break; |
340 | case MCAF_Code32: OS << '\t'<< MAI->getCode32Directive();break; | |
341 | case MCAF_Code64: OS << '\t'<< MAI->getCode64Directive();break; | |
223e47cc LB |
342 | } |
343 | EmitEOL(); | |
344 | } | |
345 | ||
970d7e83 LB |
346 | void MCAsmStreamer::EmitLinkerOptions(ArrayRef<std::string> Options) { |
347 | assert(!Options.empty() && "At least one option is required!"); | |
348 | OS << "\t.linker_option \"" << Options[0] << '"'; | |
349 | for (ArrayRef<std::string>::iterator it = Options.begin() + 1, | |
350 | ie = Options.end(); it != ie; ++it) { | |
351 | OS << ", " << '"' << *it << '"'; | |
352 | } | |
353 | OS << "\n"; | |
354 | } | |
355 | ||
223e47cc | 356 | void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) { |
1a4d82fc | 357 | if (!MAI->doesSupportDataRegionDirectives()) |
223e47cc LB |
358 | return; |
359 | switch (Kind) { | |
360 | case MCDR_DataRegion: OS << "\t.data_region"; break; | |
361 | case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break; | |
362 | case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break; | |
363 | case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break; | |
364 | case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break; | |
365 | } | |
366 | EmitEOL(); | |
367 | } | |
368 | ||
1a4d82fc JJ |
369 | void MCAsmStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, |
370 | unsigned Minor, unsigned Update) { | |
371 | switch (Kind) { | |
372 | case MCVM_IOSVersionMin: OS << "\t.ios_version_min"; break; | |
373 | case MCVM_OSXVersionMin: OS << "\t.macosx_version_min"; break; | |
374 | } | |
375 | OS << " " << Major << ", " << Minor; | |
376 | if (Update) | |
377 | OS << ", " << Update; | |
378 | EmitEOL(); | |
379 | } | |
380 | ||
223e47cc LB |
381 | void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { |
382 | // This needs to emit to a temporary string to get properly quoted | |
383 | // MCSymbols when they have spaces in them. | |
384 | OS << "\t.thumb_func"; | |
385 | // Only Mach-O hasSubsectionsViaSymbols() | |
1a4d82fc | 386 | if (MAI->hasSubsectionsViaSymbols()) |
223e47cc LB |
387 | OS << '\t' << *Func; |
388 | EmitEOL(); | |
389 | } | |
390 | ||
391 | void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { | |
392 | OS << *Symbol << " = " << *Value; | |
393 | EmitEOL(); | |
394 | ||
1a4d82fc | 395 | MCStreamer::EmitAssignment(Symbol, Value); |
223e47cc LB |
396 | } |
397 | ||
398 | void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { | |
399 | OS << ".weakref " << *Alias << ", " << *Symbol; | |
400 | EmitEOL(); | |
401 | } | |
402 | ||
1a4d82fc | 403 | bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, |
223e47cc LB |
404 | MCSymbolAttr Attribute) { |
405 | switch (Attribute) { | |
406 | case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute"); | |
407 | case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function | |
408 | case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC | |
409 | case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object | |
410 | case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object | |
411 | case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common | |
412 | case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype | |
413 | case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object | |
1a4d82fc JJ |
414 | if (!MAI->hasDotTypeDotSizeDirective()) |
415 | return false; // Symbol attribute not supported | |
223e47cc | 416 | OS << "\t.type\t" << *Symbol << ',' |
1a4d82fc | 417 | << ((MAI->getCommentString()[0] != '@') ? '@' : '%'); |
223e47cc | 418 | switch (Attribute) { |
1a4d82fc | 419 | default: return false; |
223e47cc LB |
420 | case MCSA_ELF_TypeFunction: OS << "function"; break; |
421 | case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break; | |
422 | case MCSA_ELF_TypeObject: OS << "object"; break; | |
423 | case MCSA_ELF_TypeTLS: OS << "tls_object"; break; | |
424 | case MCSA_ELF_TypeCommon: OS << "common"; break; | |
425 | case MCSA_ELF_TypeNoType: OS << "no_type"; break; | |
426 | case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; | |
427 | } | |
428 | EmitEOL(); | |
1a4d82fc | 429 | return true; |
223e47cc | 430 | case MCSA_Global: // .globl/.global |
1a4d82fc | 431 | OS << MAI->getGlobalDirective(); |
223e47cc LB |
432 | break; |
433 | case MCSA_Hidden: OS << "\t.hidden\t"; break; | |
434 | case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; | |
435 | case MCSA_Internal: OS << "\t.internal\t"; break; | |
436 | case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; | |
437 | case MCSA_Local: OS << "\t.local\t"; break; | |
85aaf69f SL |
438 | case MCSA_NoDeadStrip: |
439 | if (!MAI->hasNoDeadStrip()) | |
440 | return false; | |
441 | OS << "\t.no_dead_strip\t"; | |
442 | break; | |
223e47cc LB |
443 | case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; |
444 | case MCSA_PrivateExtern: | |
445 | OS << "\t.private_extern\t"; | |
223e47cc LB |
446 | break; |
447 | case MCSA_Protected: OS << "\t.protected\t"; break; | |
448 | case MCSA_Reference: OS << "\t.reference\t"; break; | |
85aaf69f | 449 | case MCSA_Weak: OS << MAI->getWeakDirective(); break; |
223e47cc LB |
450 | case MCSA_WeakDefinition: |
451 | OS << "\t.weak_definition\t"; | |
223e47cc LB |
452 | break; |
453 | // .weak_reference | |
1a4d82fc | 454 | case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break; |
223e47cc LB |
455 | case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; |
456 | } | |
457 | ||
458 | OS << *Symbol; | |
459 | EmitEOL(); | |
1a4d82fc JJ |
460 | |
461 | return true; | |
223e47cc LB |
462 | } |
463 | ||
464 | void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { | |
465 | OS << ".desc" << ' ' << *Symbol << ',' << DescValue; | |
466 | EmitEOL(); | |
467 | } | |
468 | ||
469 | void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { | |
470 | OS << "\t.def\t " << *Symbol << ';'; | |
471 | EmitEOL(); | |
472 | } | |
473 | ||
474 | void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) { | |
475 | OS << "\t.scl\t" << StorageClass << ';'; | |
476 | EmitEOL(); | |
477 | } | |
478 | ||
479 | void MCAsmStreamer::EmitCOFFSymbolType (int Type) { | |
480 | OS << "\t.type\t" << Type << ';'; | |
481 | EmitEOL(); | |
482 | } | |
483 | ||
484 | void MCAsmStreamer::EndCOFFSymbolDef() { | |
485 | OS << "\t.endef"; | |
486 | EmitEOL(); | |
487 | } | |
488 | ||
1a4d82fc JJ |
489 | void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { |
490 | OS << "\t.secidx\t" << *Symbol; | |
491 | EmitEOL(); | |
492 | } | |
493 | ||
223e47cc | 494 | void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { |
1a4d82fc | 495 | OS << "\t.secrel32\t" << *Symbol; |
223e47cc LB |
496 | EmitEOL(); |
497 | } | |
498 | ||
499 | void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { | |
1a4d82fc | 500 | assert(MAI->hasDotTypeDotSizeDirective()); |
223e47cc LB |
501 | OS << "\t.size\t" << *Symbol << ", " << *Value << '\n'; |
502 | } | |
503 | ||
504 | void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, | |
505 | unsigned ByteAlignment) { | |
1a4d82fc JJ |
506 | // Common symbols do not belong to any actual section. |
507 | AssignSection(Symbol, nullptr); | |
508 | ||
223e47cc LB |
509 | OS << "\t.comm\t" << *Symbol << ',' << Size; |
510 | if (ByteAlignment != 0) { | |
1a4d82fc | 511 | if (MAI->getCOMMDirectiveAlignmentIsInBytes()) |
223e47cc LB |
512 | OS << ',' << ByteAlignment; |
513 | else | |
514 | OS << ',' << Log2_32(ByteAlignment); | |
515 | } | |
516 | EmitEOL(); | |
517 | } | |
518 | ||
519 | /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. | |
520 | /// | |
521 | /// @param Symbol - The common symbol to emit. | |
522 | /// @param Size - The size of the common symbol. | |
523 | void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, | |
524 | unsigned ByteAlign) { | |
1a4d82fc JJ |
525 | // Common symbols do not belong to any actual section. |
526 | AssignSection(Symbol, nullptr); | |
527 | ||
223e47cc LB |
528 | OS << "\t.lcomm\t" << *Symbol << ',' << Size; |
529 | if (ByteAlign > 1) { | |
1a4d82fc | 530 | switch (MAI->getLCOMMDirectiveAlignmentType()) { |
223e47cc LB |
531 | case LCOMM::NoAlignment: |
532 | llvm_unreachable("alignment not supported on .lcomm!"); | |
533 | case LCOMM::ByteAlignment: | |
534 | OS << ',' << ByteAlign; | |
535 | break; | |
536 | case LCOMM::Log2Alignment: | |
537 | assert(isPowerOf2_32(ByteAlign) && "alignment must be a power of 2"); | |
538 | OS << ',' << Log2_32(ByteAlign); | |
539 | break; | |
540 | } | |
541 | } | |
542 | EmitEOL(); | |
543 | } | |
544 | ||
545 | void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, | |
546 | uint64_t Size, unsigned ByteAlignment) { | |
1a4d82fc JJ |
547 | if (Symbol) |
548 | AssignSection(Symbol, Section); | |
549 | ||
223e47cc LB |
550 | // Note: a .zerofill directive does not switch sections. |
551 | OS << ".zerofill "; | |
552 | ||
553 | // This is a mach-o specific directive. | |
554 | const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); | |
555 | OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); | |
556 | ||
1a4d82fc | 557 | if (Symbol) { |
223e47cc LB |
558 | OS << ',' << *Symbol << ',' << Size; |
559 | if (ByteAlignment != 0) | |
560 | OS << ',' << Log2_32(ByteAlignment); | |
561 | } | |
562 | EmitEOL(); | |
563 | } | |
564 | ||
565 | // .tbss sym, size, align | |
566 | // This depends that the symbol has already been mangled from the original, | |
567 | // e.g. _a. | |
568 | void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, | |
569 | uint64_t Size, unsigned ByteAlignment) { | |
1a4d82fc JJ |
570 | AssignSection(Symbol, Section); |
571 | ||
572 | assert(Symbol && "Symbol shouldn't be NULL!"); | |
223e47cc LB |
573 | // Instead of using the Section we'll just use the shortcut. |
574 | // This is a mach-o specific directive and section. | |
575 | OS << ".tbss " << *Symbol << ", " << Size; | |
576 | ||
577 | // Output align if we have it. We default to 1 so don't bother printing | |
578 | // that. | |
579 | if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment); | |
580 | ||
581 | EmitEOL(); | |
582 | } | |
583 | ||
584 | static inline char toOctal(int X) { return (X&7)+'0'; } | |
585 | ||
586 | static void PrintQuotedString(StringRef Data, raw_ostream &OS) { | |
587 | OS << '"'; | |
588 | ||
589 | for (unsigned i = 0, e = Data.size(); i != e; ++i) { | |
590 | unsigned char C = Data[i]; | |
591 | if (C == '"' || C == '\\') { | |
592 | OS << '\\' << (char)C; | |
593 | continue; | |
594 | } | |
595 | ||
596 | if (isprint((unsigned char)C)) { | |
597 | OS << (char)C; | |
598 | continue; | |
599 | } | |
600 | ||
601 | switch (C) { | |
602 | case '\b': OS << "\\b"; break; | |
603 | case '\f': OS << "\\f"; break; | |
604 | case '\n': OS << "\\n"; break; | |
605 | case '\r': OS << "\\r"; break; | |
606 | case '\t': OS << "\\t"; break; | |
607 | default: | |
608 | OS << '\\'; | |
609 | OS << toOctal(C >> 6); | |
610 | OS << toOctal(C >> 3); | |
611 | OS << toOctal(C >> 0); | |
612 | break; | |
613 | } | |
614 | } | |
615 | ||
616 | OS << '"'; | |
617 | } | |
618 | ||
619 | ||
1a4d82fc JJ |
620 | void MCAsmStreamer::EmitBytes(StringRef Data) { |
621 | assert(getCurrentSection().first && | |
622 | "Cannot emit contents before setting section!"); | |
223e47cc LB |
623 | if (Data.empty()) return; |
624 | ||
625 | if (Data.size() == 1) { | |
1a4d82fc | 626 | OS << MAI->getData8bitsDirective(); |
223e47cc LB |
627 | OS << (unsigned)(unsigned char)Data[0]; |
628 | EmitEOL(); | |
629 | return; | |
630 | } | |
631 | ||
632 | // If the data ends with 0 and the target supports .asciz, use it, otherwise | |
633 | // use .ascii | |
1a4d82fc JJ |
634 | if (MAI->getAscizDirective() && Data.back() == 0) { |
635 | OS << MAI->getAscizDirective(); | |
223e47cc LB |
636 | Data = Data.substr(0, Data.size()-1); |
637 | } else { | |
1a4d82fc | 638 | OS << MAI->getAsciiDirective(); |
223e47cc LB |
639 | } |
640 | ||
223e47cc LB |
641 | PrintQuotedString(Data, OS); |
642 | EmitEOL(); | |
643 | } | |
644 | ||
1a4d82fc JJ |
645 | void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) { |
646 | EmitValue(MCConstantExpr::Create(Value, getContext()), Size); | |
223e47cc LB |
647 | } |
648 | ||
649 | void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, | |
1a4d82fc JJ |
650 | const SMLoc &Loc) { |
651 | assert(Size <= 8 && "Invalid size"); | |
652 | assert(getCurrentSection().first && | |
653 | "Cannot emit contents before setting section!"); | |
654 | const char *Directive = nullptr; | |
223e47cc LB |
655 | switch (Size) { |
656 | default: break; | |
1a4d82fc JJ |
657 | case 1: Directive = MAI->getData8bitsDirective(); break; |
658 | case 2: Directive = MAI->getData16bitsDirective(); break; | |
659 | case 4: Directive = MAI->getData32bitsDirective(); break; | |
660 | case 8: Directive = MAI->getData64bitsDirective(); break; | |
661 | } | |
662 | ||
663 | if (!Directive) { | |
223e47cc LB |
664 | int64_t IntValue; |
665 | if (!Value->EvaluateAsAbsolute(IntValue)) | |
666 | report_fatal_error("Don't know how to emit this value."); | |
1a4d82fc JJ |
667 | |
668 | // We couldn't handle the requested integer size so we fallback by breaking | |
669 | // the request down into several, smaller, integers. Since sizes greater | |
670 | // than eight are invalid and size equivalent to eight should have been | |
671 | // handled earlier, we use four bytes as our largest piece of granularity. | |
672 | bool IsLittleEndian = MAI->isLittleEndian(); | |
673 | for (unsigned Emitted = 0; Emitted != Size;) { | |
674 | unsigned Remaining = Size - Emitted; | |
675 | // The size of our partial emission must be a power of two less than | |
676 | // eight. | |
677 | unsigned EmissionSize = PowerOf2Floor(Remaining); | |
678 | if (EmissionSize > 4) | |
679 | EmissionSize = 4; | |
680 | // Calculate the byte offset of our partial emission taking into account | |
681 | // the endianness of the target. | |
682 | unsigned ByteOffset = | |
683 | IsLittleEndian ? Emitted : (Remaining - EmissionSize); | |
684 | uint64_t ValueToEmit = IntValue >> (ByteOffset * 8); | |
685 | // We truncate our partial emission to fit within the bounds of the | |
686 | // emission domain. This produces nicer output and silences potential | |
687 | // truncation warnings when round tripping through another assembler. | |
85aaf69f SL |
688 | uint64_t Shift = 64 - EmissionSize * 8; |
689 | assert(Shift < static_cast<uint64_t>( | |
690 | std::numeric_limits<unsigned long long>::digits) && | |
691 | "undefined behavior"); | |
692 | ValueToEmit &= ~0ULL >> Shift; | |
1a4d82fc JJ |
693 | EmitIntValue(ValueToEmit, EmissionSize); |
694 | Emitted += EmissionSize; | |
223e47cc LB |
695 | } |
696 | return; | |
697 | } | |
698 | ||
699 | assert(Directive && "Invalid size for machine code value!"); | |
700 | OS << Directive << *Value; | |
701 | EmitEOL(); | |
702 | } | |
703 | ||
704 | void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) { | |
705 | int64_t IntValue; | |
706 | if (Value->EvaluateAsAbsolute(IntValue)) { | |
707 | EmitULEB128IntValue(IntValue); | |
708 | return; | |
709 | } | |
223e47cc LB |
710 | OS << ".uleb128 " << *Value; |
711 | EmitEOL(); | |
712 | } | |
713 | ||
714 | void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { | |
715 | int64_t IntValue; | |
716 | if (Value->EvaluateAsAbsolute(IntValue)) { | |
717 | EmitSLEB128IntValue(IntValue); | |
718 | return; | |
719 | } | |
223e47cc LB |
720 | OS << ".sleb128 " << *Value; |
721 | EmitEOL(); | |
722 | } | |
723 | ||
724 | void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { | |
1a4d82fc JJ |
725 | assert(MAI->getGPRel64Directive() != nullptr); |
726 | OS << MAI->getGPRel64Directive() << *Value; | |
223e47cc LB |
727 | EmitEOL(); |
728 | } | |
729 | ||
730 | void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { | |
1a4d82fc JJ |
731 | assert(MAI->getGPRel32Directive() != nullptr); |
732 | OS << MAI->getGPRel32Directive() << *Value; | |
223e47cc LB |
733 | EmitEOL(); |
734 | } | |
735 | ||
736 | ||
737 | /// EmitFill - Emit NumBytes bytes worth of the value specified by | |
738 | /// FillValue. This implements directives such as '.space'. | |
1a4d82fc | 739 | void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) { |
223e47cc LB |
740 | if (NumBytes == 0) return; |
741 | ||
1a4d82fc JJ |
742 | if (const char *ZeroDirective = MAI->getZeroDirective()) { |
743 | OS << ZeroDirective << NumBytes; | |
744 | if (FillValue != 0) | |
745 | OS << ',' << (int)FillValue; | |
746 | EmitEOL(); | |
747 | return; | |
748 | } | |
223e47cc LB |
749 | |
750 | // Emit a byte at a time. | |
1a4d82fc | 751 | MCStreamer::EmitFill(NumBytes, FillValue); |
223e47cc LB |
752 | } |
753 | ||
754 | void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, | |
755 | unsigned ValueSize, | |
756 | unsigned MaxBytesToEmit) { | |
757 | // Some assemblers don't support non-power of two alignments, so we always | |
758 | // emit alignments as a power of two if possible. | |
759 | if (isPowerOf2_32(ByteAlignment)) { | |
760 | switch (ValueSize) { | |
1a4d82fc JJ |
761 | default: |
762 | llvm_unreachable("Invalid size for machine code value!"); | |
763 | case 1: | |
764 | OS << "\t.align\t"; | |
765 | break; | |
766 | case 2: | |
767 | OS << ".p2alignw "; | |
768 | break; | |
769 | case 4: | |
770 | OS << ".p2alignl "; | |
771 | break; | |
772 | case 8: | |
773 | llvm_unreachable("Unsupported alignment size!"); | |
223e47cc LB |
774 | } |
775 | ||
1a4d82fc | 776 | if (MAI->getAlignmentIsInBytes()) |
223e47cc LB |
777 | OS << ByteAlignment; |
778 | else | |
779 | OS << Log2_32(ByteAlignment); | |
780 | ||
781 | if (Value || MaxBytesToEmit) { | |
782 | OS << ", 0x"; | |
783 | OS.write_hex(truncateToSize(Value, ValueSize)); | |
784 | ||
785 | if (MaxBytesToEmit) | |
786 | OS << ", " << MaxBytesToEmit; | |
787 | } | |
788 | EmitEOL(); | |
789 | return; | |
790 | } | |
791 | ||
792 | // Non-power of two alignment. This is not widely supported by assemblers. | |
793 | // FIXME: Parameterize this based on MAI. | |
794 | switch (ValueSize) { | |
795 | default: llvm_unreachable("Invalid size for machine code value!"); | |
796 | case 1: OS << ".balign"; break; | |
797 | case 2: OS << ".balignw"; break; | |
798 | case 4: OS << ".balignl"; break; | |
799 | case 8: llvm_unreachable("Unsupported alignment size!"); | |
800 | } | |
801 | ||
802 | OS << ' ' << ByteAlignment; | |
803 | OS << ", " << truncateToSize(Value, ValueSize); | |
804 | if (MaxBytesToEmit) | |
805 | OS << ", " << MaxBytesToEmit; | |
806 | EmitEOL(); | |
807 | } | |
808 | ||
809 | void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, | |
810 | unsigned MaxBytesToEmit) { | |
811 | // Emit with a text fill value. | |
1a4d82fc | 812 | EmitValueToAlignment(ByteAlignment, MAI->getTextAlignFillValue(), |
223e47cc LB |
813 | 1, MaxBytesToEmit); |
814 | } | |
815 | ||
816 | bool MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, | |
817 | unsigned char Value) { | |
818 | // FIXME: Verify that Offset is associated with the current section. | |
819 | OS << ".org " << *Offset << ", " << (unsigned) Value; | |
820 | EmitEOL(); | |
821 | return false; | |
822 | } | |
823 | ||
824 | ||
825 | void MCAsmStreamer::EmitFileDirective(StringRef Filename) { | |
1a4d82fc | 826 | assert(MAI->hasSingleParameterDotFile()); |
223e47cc LB |
827 | OS << "\t.file\t"; |
828 | PrintQuotedString(Filename, OS); | |
829 | EmitEOL(); | |
830 | } | |
831 | ||
1a4d82fc JJ |
832 | unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, |
833 | StringRef Directory, | |
834 | StringRef Filename, | |
835 | unsigned CUID) { | |
836 | assert(CUID == 0); | |
837 | ||
838 | MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); | |
839 | unsigned NumFiles = Table.getMCDwarfFiles().size(); | |
840 | FileNo = Table.getFile(Directory, Filename, FileNo); | |
841 | if (FileNo == 0) | |
842 | return 0; | |
843 | if (NumFiles == Table.getMCDwarfFiles().size()) | |
844 | return FileNo; | |
845 | ||
846 | SmallString<128> FullPathName; | |
847 | ||
223e47cc LB |
848 | if (!UseDwarfDirectory && !Directory.empty()) { |
849 | if (sys::path::is_absolute(Filename)) | |
1a4d82fc JJ |
850 | Directory = ""; |
851 | else { | |
852 | FullPathName = Directory; | |
853 | sys::path::append(FullPathName, Filename); | |
854 | Directory = ""; | |
855 | Filename = FullPathName; | |
856 | } | |
223e47cc LB |
857 | } |
858 | ||
1a4d82fc JJ |
859 | OS << "\t.file\t" << FileNo << ' '; |
860 | if (!Directory.empty()) { | |
861 | PrintQuotedString(Directory, OS); | |
862 | OS << ' '; | |
223e47cc | 863 | } |
1a4d82fc JJ |
864 | PrintQuotedString(Filename, OS); |
865 | EmitEOL(); | |
866 | ||
867 | return FileNo; | |
223e47cc LB |
868 | } |
869 | ||
870 | void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, | |
871 | unsigned Column, unsigned Flags, | |
872 | unsigned Isa, | |
873 | unsigned Discriminator, | |
874 | StringRef FileName) { | |
223e47cc LB |
875 | OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; |
876 | if (Flags & DWARF2_FLAG_BASIC_BLOCK) | |
877 | OS << " basic_block"; | |
878 | if (Flags & DWARF2_FLAG_PROLOGUE_END) | |
879 | OS << " prologue_end"; | |
880 | if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) | |
881 | OS << " epilogue_begin"; | |
882 | ||
883 | unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); | |
884 | if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { | |
885 | OS << " is_stmt "; | |
886 | ||
887 | if (Flags & DWARF2_FLAG_IS_STMT) | |
888 | OS << "1"; | |
889 | else | |
890 | OS << "0"; | |
891 | } | |
892 | ||
893 | if (Isa) | |
1a4d82fc | 894 | OS << " isa " << Isa; |
223e47cc | 895 | if (Discriminator) |
1a4d82fc | 896 | OS << " discriminator " << Discriminator; |
223e47cc LB |
897 | |
898 | if (IsVerboseAsm) { | |
1a4d82fc JJ |
899 | OS.PadToColumn(MAI->getCommentColumn()); |
900 | OS << MAI->getCommentString() << ' ' << FileName << ':' | |
223e47cc LB |
901 | << Line << ':' << Column; |
902 | } | |
903 | EmitEOL(); | |
85aaf69f SL |
904 | this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, |
905 | Isa, Discriminator, FileName); | |
223e47cc LB |
906 | } |
907 | ||
1a4d82fc JJ |
908 | MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) { |
909 | // Always use the zeroth line table, since asm syntax only supports one line | |
910 | // table for now. | |
911 | return MCStreamer::getDwarfLineTableSymbol(0); | |
912 | } | |
223e47cc | 913 | |
1a4d82fc JJ |
914 | void MCAsmStreamer::EmitIdent(StringRef IdentString) { |
915 | assert(MAI->hasIdentDirective() && ".ident directive not supported"); | |
916 | OS << "\t.ident\t"; | |
917 | PrintQuotedString(IdentString, OS); | |
918 | EmitEOL(); | |
919 | } | |
223e47cc | 920 | |
1a4d82fc JJ |
921 | void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) { |
922 | MCStreamer::EmitCFISections(EH, Debug); | |
223e47cc LB |
923 | OS << "\t.cfi_sections "; |
924 | if (EH) { | |
925 | OS << ".eh_frame"; | |
926 | if (Debug) | |
927 | OS << ", .debug_frame"; | |
928 | } else if (Debug) { | |
929 | OS << ".debug_frame"; | |
930 | } | |
931 | ||
932 | EmitEOL(); | |
933 | } | |
934 | ||
935 | void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { | |
223e47cc | 936 | OS << "\t.cfi_startproc"; |
1a4d82fc JJ |
937 | if (Frame.IsSimple) |
938 | OS << " simple"; | |
223e47cc LB |
939 | EmitEOL(); |
940 | } | |
941 | ||
942 | void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { | |
1a4d82fc | 943 | MCStreamer::EmitCFIEndProcImpl(Frame); |
223e47cc LB |
944 | OS << "\t.cfi_endproc"; |
945 | EmitEOL(); | |
946 | } | |
947 | ||
948 | void MCAsmStreamer::EmitRegisterName(int64_t Register) { | |
1a4d82fc JJ |
949 | if (InstPrinter && !MAI->useDwarfRegNumForCFI()) { |
950 | const MCRegisterInfo *MRI = getContext().getRegisterInfo(); | |
951 | unsigned LLVMRegister = MRI->getLLVMRegNum(Register, true); | |
223e47cc LB |
952 | InstPrinter->printRegName(OS, LLVMRegister); |
953 | } else { | |
954 | OS << Register; | |
955 | } | |
956 | } | |
957 | ||
958 | void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { | |
959 | MCStreamer::EmitCFIDefCfa(Register, Offset); | |
223e47cc LB |
960 | OS << "\t.cfi_def_cfa "; |
961 | EmitRegisterName(Register); | |
962 | OS << ", " << Offset; | |
963 | EmitEOL(); | |
964 | } | |
965 | ||
966 | void MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { | |
967 | MCStreamer::EmitCFIDefCfaOffset(Offset); | |
223e47cc LB |
968 | OS << "\t.cfi_def_cfa_offset " << Offset; |
969 | EmitEOL(); | |
970 | } | |
971 | ||
972 | void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { | |
973 | MCStreamer::EmitCFIDefCfaRegister(Register); | |
223e47cc LB |
974 | OS << "\t.cfi_def_cfa_register "; |
975 | EmitRegisterName(Register); | |
976 | EmitEOL(); | |
977 | } | |
978 | ||
979 | void MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { | |
980 | this->MCStreamer::EmitCFIOffset(Register, Offset); | |
223e47cc LB |
981 | OS << "\t.cfi_offset "; |
982 | EmitRegisterName(Register); | |
983 | OS << ", " << Offset; | |
984 | EmitEOL(); | |
985 | } | |
986 | ||
987 | void MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, | |
988 | unsigned Encoding) { | |
989 | MCStreamer::EmitCFIPersonality(Sym, Encoding); | |
223e47cc LB |
990 | OS << "\t.cfi_personality " << Encoding << ", " << *Sym; |
991 | EmitEOL(); | |
992 | } | |
993 | ||
994 | void MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { | |
995 | MCStreamer::EmitCFILsda(Sym, Encoding); | |
223e47cc LB |
996 | OS << "\t.cfi_lsda " << Encoding << ", " << *Sym; |
997 | EmitEOL(); | |
998 | } | |
999 | ||
1000 | void MCAsmStreamer::EmitCFIRememberState() { | |
1001 | MCStreamer::EmitCFIRememberState(); | |
223e47cc LB |
1002 | OS << "\t.cfi_remember_state"; |
1003 | EmitEOL(); | |
1004 | } | |
1005 | ||
1006 | void MCAsmStreamer::EmitCFIRestoreState() { | |
1007 | MCStreamer::EmitCFIRestoreState(); | |
223e47cc LB |
1008 | OS << "\t.cfi_restore_state"; |
1009 | EmitEOL(); | |
1010 | } | |
1011 | ||
1012 | void MCAsmStreamer::EmitCFISameValue(int64_t Register) { | |
1013 | MCStreamer::EmitCFISameValue(Register); | |
223e47cc LB |
1014 | OS << "\t.cfi_same_value "; |
1015 | EmitRegisterName(Register); | |
1016 | EmitEOL(); | |
1017 | } | |
1018 | ||
1019 | void MCAsmStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { | |
1020 | MCStreamer::EmitCFIRelOffset(Register, Offset); | |
223e47cc LB |
1021 | OS << "\t.cfi_rel_offset "; |
1022 | EmitRegisterName(Register); | |
1023 | OS << ", " << Offset; | |
1024 | EmitEOL(); | |
1025 | } | |
1026 | ||
1027 | void MCAsmStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { | |
1028 | MCStreamer::EmitCFIAdjustCfaOffset(Adjustment); | |
223e47cc LB |
1029 | OS << "\t.cfi_adjust_cfa_offset " << Adjustment; |
1030 | EmitEOL(); | |
1031 | } | |
1032 | ||
1033 | void MCAsmStreamer::EmitCFISignalFrame() { | |
1034 | MCStreamer::EmitCFISignalFrame(); | |
223e47cc LB |
1035 | OS << "\t.cfi_signal_frame"; |
1036 | EmitEOL(); | |
1037 | } | |
1038 | ||
970d7e83 LB |
1039 | void MCAsmStreamer::EmitCFIUndefined(int64_t Register) { |
1040 | MCStreamer::EmitCFIUndefined(Register); | |
970d7e83 LB |
1041 | OS << "\t.cfi_undefined " << Register; |
1042 | EmitEOL(); | |
1043 | } | |
1044 | ||
1045 | void MCAsmStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { | |
1046 | MCStreamer::EmitCFIRegister(Register1, Register2); | |
970d7e83 LB |
1047 | OS << "\t.cfi_register " << Register1 << ", " << Register2; |
1048 | EmitEOL(); | |
1049 | } | |
1050 | ||
1a4d82fc JJ |
1051 | void MCAsmStreamer::EmitCFIWindowSave() { |
1052 | MCStreamer::EmitCFIWindowSave(); | |
1053 | OS << "\t.cfi_window_save"; | |
1054 | EmitEOL(); | |
1055 | } | |
1056 | ||
1057 | void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol) { | |
1058 | MCStreamer::EmitWinCFIStartProc(Symbol); | |
223e47cc LB |
1059 | |
1060 | OS << ".seh_proc " << *Symbol; | |
1061 | EmitEOL(); | |
1062 | } | |
1063 | ||
1a4d82fc JJ |
1064 | void MCAsmStreamer::EmitWinCFIEndProc() { |
1065 | MCStreamer::EmitWinCFIEndProc(); | |
223e47cc LB |
1066 | |
1067 | OS << "\t.seh_endproc"; | |
1068 | EmitEOL(); | |
1069 | } | |
1070 | ||
1a4d82fc JJ |
1071 | void MCAsmStreamer::EmitWinCFIStartChained() { |
1072 | MCStreamer::EmitWinCFIStartChained(); | |
223e47cc LB |
1073 | |
1074 | OS << "\t.seh_startchained"; | |
1075 | EmitEOL(); | |
1076 | } | |
1077 | ||
1a4d82fc JJ |
1078 | void MCAsmStreamer::EmitWinCFIEndChained() { |
1079 | MCStreamer::EmitWinCFIEndChained(); | |
223e47cc LB |
1080 | |
1081 | OS << "\t.seh_endchained"; | |
1082 | EmitEOL(); | |
1083 | } | |
1084 | ||
1a4d82fc JJ |
1085 | void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, |
1086 | bool Except) { | |
1087 | MCStreamer::EmitWinEHHandler(Sym, Unwind, Except); | |
223e47cc LB |
1088 | |
1089 | OS << "\t.seh_handler " << *Sym; | |
1090 | if (Unwind) | |
1091 | OS << ", @unwind"; | |
1092 | if (Except) | |
1093 | OS << ", @except"; | |
1094 | EmitEOL(); | |
1095 | } | |
1096 | ||
1a4d82fc JJ |
1097 | void MCAsmStreamer::EmitWinEHHandlerData() { |
1098 | MCStreamer::EmitWinEHHandlerData(); | |
223e47cc LB |
1099 | |
1100 | // Switch sections. Don't call SwitchSection directly, because that will | |
1101 | // cause the section switch to be visible in the emitted assembly. | |
1102 | // We only do this so the section switch that terminates the handler | |
1103 | // data block is visible. | |
1a4d82fc JJ |
1104 | WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo(); |
1105 | if (const MCSection *XData = WinEH::UnwindEmitter::getXDataSection( | |
1106 | CurFrame->Function, getContext())) | |
1107 | SwitchSectionNoChange(XData); | |
223e47cc LB |
1108 | |
1109 | OS << "\t.seh_handlerdata"; | |
1110 | EmitEOL(); | |
1111 | } | |
1112 | ||
1a4d82fc JJ |
1113 | void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register) { |
1114 | MCStreamer::EmitWinCFIPushReg(Register); | |
223e47cc LB |
1115 | |
1116 | OS << "\t.seh_pushreg " << Register; | |
1117 | EmitEOL(); | |
1118 | } | |
1119 | ||
1a4d82fc JJ |
1120 | void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset) { |
1121 | MCStreamer::EmitWinCFISetFrame(Register, Offset); | |
223e47cc LB |
1122 | |
1123 | OS << "\t.seh_setframe " << Register << ", " << Offset; | |
1124 | EmitEOL(); | |
1125 | } | |
1126 | ||
1a4d82fc JJ |
1127 | void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size) { |
1128 | MCStreamer::EmitWinCFIAllocStack(Size); | |
223e47cc LB |
1129 | |
1130 | OS << "\t.seh_stackalloc " << Size; | |
1131 | EmitEOL(); | |
1132 | } | |
1133 | ||
1a4d82fc JJ |
1134 | void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset) { |
1135 | MCStreamer::EmitWinCFISaveReg(Register, Offset); | |
223e47cc LB |
1136 | |
1137 | OS << "\t.seh_savereg " << Register << ", " << Offset; | |
1138 | EmitEOL(); | |
1139 | } | |
1140 | ||
1a4d82fc JJ |
1141 | void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset) { |
1142 | MCStreamer::EmitWinCFISaveXMM(Register, Offset); | |
223e47cc LB |
1143 | |
1144 | OS << "\t.seh_savexmm " << Register << ", " << Offset; | |
1145 | EmitEOL(); | |
1146 | } | |
1147 | ||
1a4d82fc JJ |
1148 | void MCAsmStreamer::EmitWinCFIPushFrame(bool Code) { |
1149 | MCStreamer::EmitWinCFIPushFrame(Code); | |
223e47cc LB |
1150 | |
1151 | OS << "\t.seh_pushframe"; | |
1152 | if (Code) | |
1153 | OS << " @code"; | |
1154 | EmitEOL(); | |
1155 | } | |
1156 | ||
1a4d82fc JJ |
1157 | void MCAsmStreamer::EmitWinCFIEndProlog(void) { |
1158 | MCStreamer::EmitWinCFIEndProlog(); | |
223e47cc LB |
1159 | |
1160 | OS << "\t.seh_endprologue"; | |
1161 | EmitEOL(); | |
1162 | } | |
1163 | ||
1a4d82fc JJ |
1164 | void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, |
1165 | const MCSubtargetInfo &STI) { | |
223e47cc LB |
1166 | raw_ostream &OS = GetCommentOS(); |
1167 | SmallString<256> Code; | |
1168 | SmallVector<MCFixup, 4> Fixups; | |
1169 | raw_svector_ostream VecOS(Code); | |
1a4d82fc | 1170 | Emitter->EncodeInstruction(Inst, VecOS, Fixups, STI); |
223e47cc LB |
1171 | VecOS.flush(); |
1172 | ||
1173 | // If we are showing fixups, create symbolic markers in the encoded | |
1174 | // representation. We do this by making a per-bit map to the fixup item index, | |
1175 | // then trying to display it as nicely as possible. | |
1176 | SmallVector<uint8_t, 64> FixupMap; | |
1177 | FixupMap.resize(Code.size() * 8); | |
1178 | for (unsigned i = 0, e = Code.size() * 8; i != e; ++i) | |
1179 | FixupMap[i] = 0; | |
1180 | ||
1181 | for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { | |
1182 | MCFixup &F = Fixups[i]; | |
1183 | const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); | |
1184 | for (unsigned j = 0; j != Info.TargetSize; ++j) { | |
1185 | unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; | |
1186 | assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); | |
1187 | FixupMap[Index] = 1 + i; | |
1188 | } | |
1189 | } | |
1190 | ||
1191 | // FIXME: Note the fixup comments for Thumb2 are completely bogus since the | |
1192 | // high order halfword of a 32-bit Thumb2 instruction is emitted first. | |
1193 | OS << "encoding: ["; | |
1194 | for (unsigned i = 0, e = Code.size(); i != e; ++i) { | |
1195 | if (i) | |
1196 | OS << ','; | |
1197 | ||
1198 | // See if all bits are the same map entry. | |
1199 | uint8_t MapEntry = FixupMap[i * 8 + 0]; | |
1200 | for (unsigned j = 1; j != 8; ++j) { | |
1201 | if (FixupMap[i * 8 + j] == MapEntry) | |
1202 | continue; | |
1203 | ||
1204 | MapEntry = uint8_t(~0U); | |
1205 | break; | |
1206 | } | |
1207 | ||
1208 | if (MapEntry != uint8_t(~0U)) { | |
1209 | if (MapEntry == 0) { | |
1210 | OS << format("0x%02x", uint8_t(Code[i])); | |
1211 | } else { | |
1212 | if (Code[i]) { | |
1213 | // FIXME: Some of the 8 bits require fix up. | |
1214 | OS << format("0x%02x", uint8_t(Code[i])) << '\'' | |
1215 | << char('A' + MapEntry - 1) << '\''; | |
1216 | } else | |
1217 | OS << char('A' + MapEntry - 1); | |
1218 | } | |
1219 | } else { | |
1220 | // Otherwise, write out in binary. | |
1221 | OS << "0b"; | |
1222 | for (unsigned j = 8; j--;) { | |
1223 | unsigned Bit = (Code[i] >> j) & 1; | |
1224 | ||
1225 | unsigned FixupBit; | |
1a4d82fc | 1226 | if (MAI->isLittleEndian()) |
223e47cc LB |
1227 | FixupBit = i * 8 + j; |
1228 | else | |
1229 | FixupBit = i * 8 + (7-j); | |
1230 | ||
1231 | if (uint8_t MapEntry = FixupMap[FixupBit]) { | |
1232 | assert(Bit == 0 && "Encoder wrote into fixed up bit!"); | |
1233 | OS << char('A' + MapEntry - 1); | |
1234 | } else | |
1235 | OS << Bit; | |
1236 | } | |
1237 | } | |
1238 | } | |
1239 | OS << "]\n"; | |
1240 | ||
1241 | for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { | |
1242 | MCFixup &F = Fixups[i]; | |
1243 | const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); | |
1244 | OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() | |
1245 | << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; | |
1246 | } | |
1247 | } | |
1248 | ||
1a4d82fc JJ |
1249 | void MCAsmStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { |
1250 | assert(getCurrentSection().first && | |
1251 | "Cannot emit contents before setting section!"); | |
223e47cc LB |
1252 | |
1253 | // Show the encoding in a comment if we have a code emitter. | |
1254 | if (Emitter) | |
1a4d82fc | 1255 | AddEncodingComment(Inst, STI); |
223e47cc LB |
1256 | |
1257 | // Show the MCInst if enabled. | |
1258 | if (ShowInst) { | |
1a4d82fc | 1259 | Inst.dump_pretty(GetCommentOS(), MAI, InstPrinter.get(), "\n "); |
223e47cc LB |
1260 | GetCommentOS() << "\n"; |
1261 | } | |
1262 | ||
1263 | // If we have an AsmPrinter, use that to print, otherwise print the MCInst. | |
1264 | if (InstPrinter) | |
1265 | InstPrinter->printInst(&Inst, OS, ""); | |
1266 | else | |
1a4d82fc | 1267 | Inst.print(OS, MAI); |
223e47cc LB |
1268 | EmitEOL(); |
1269 | } | |
1270 | ||
970d7e83 LB |
1271 | void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) { |
1272 | OS << "\t.bundle_align_mode " << AlignPow2; | |
1273 | EmitEOL(); | |
1274 | } | |
1275 | ||
1276 | void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) { | |
1277 | OS << "\t.bundle_lock"; | |
1278 | if (AlignToEnd) | |
1279 | OS << " align_to_end"; | |
1280 | EmitEOL(); | |
1281 | } | |
1282 | ||
1283 | void MCAsmStreamer::EmitBundleUnlock() { | |
1284 | OS << "\t.bundle_unlock"; | |
1285 | EmitEOL(); | |
1286 | } | |
1287 | ||
223e47cc LB |
1288 | /// EmitRawText - If this file is backed by an assembly streamer, this dumps |
1289 | /// the specified string in the output .s file. This capability is | |
1290 | /// indicated by the hasRawTextSupport() predicate. | |
1a4d82fc | 1291 | void MCAsmStreamer::EmitRawTextImpl(StringRef String) { |
223e47cc LB |
1292 | if (!String.empty() && String.back() == '\n') |
1293 | String = String.substr(0, String.size()-1); | |
1294 | OS << String; | |
1295 | EmitEOL(); | |
1296 | } | |
1297 | ||
1298 | void MCAsmStreamer::FinishImpl() { | |
223e47cc LB |
1299 | // If we are generating dwarf for assembly source files dump out the sections. |
1300 | if (getContext().getGenDwarfForAssembly()) | |
1a4d82fc JJ |
1301 | MCGenDwarfInfo::Emit(this); |
1302 | ||
1303 | // Emit the label for the line table, if requested - since the rest of the | |
1304 | // line table will be defined by .loc/.file directives, and not emitted | |
1305 | // directly, the label is the only work required here. | |
1306 | auto &Tables = getContext().getMCDwarfLineTables(); | |
1307 | if (!Tables.empty()) { | |
1308 | assert(Tables.size() == 1 && "asm output only supports one line table"); | |
1309 | if (auto *Label = Tables.begin()->second.getLabel()) { | |
1310 | SwitchSection(getContext().getObjectFileInfo()->getDwarfLineSection()); | |
1311 | EmitLabel(Label); | |
1312 | } | |
1313 | } | |
223e47cc | 1314 | } |
1a4d82fc | 1315 | |
223e47cc LB |
1316 | MCStreamer *llvm::createAsmStreamer(MCContext &Context, |
1317 | formatted_raw_ostream &OS, | |
1a4d82fc | 1318 | bool isVerboseAsm, bool useDwarfDirectory, |
223e47cc LB |
1319 | MCInstPrinter *IP, MCCodeEmitter *CE, |
1320 | MCAsmBackend *MAB, bool ShowInst) { | |
1a4d82fc JJ |
1321 | return new MCAsmStreamer(Context, OS, isVerboseAsm, useDwarfDirectory, IP, CE, |
1322 | MAB, ShowInst); | |
223e47cc | 1323 | } |