xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
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 // This file implements the inline assembler pieces of the AsmPrinter class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/Twine.h"
16 #include "llvm/CodeGen/AsmPrinter.h"
17 #include "llvm/CodeGen/MachineBasicBlock.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/CodeGen/MachineModuleInfo.h"
20 #include "llvm/CodeGen/TargetInstrInfo.h"
21 #include "llvm/CodeGen/TargetRegisterInfo.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DataLayout.h"
24 #include "llvm/IR/DiagnosticInfo.h"
25 #include "llvm/IR/InlineAsm.h"
26 #include "llvm/IR/LLVMContext.h"
27 #include "llvm/IR/Module.h"
28 #include "llvm/MC/MCAsmInfo.h"
29 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/MC/MCSubtargetInfo.h"
32 #include "llvm/MC/MCSymbol.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/MemoryBuffer.h"
35 #include "llvm/Support/SourceMgr.h"
36 #include "llvm/Support/TargetRegistry.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include "llvm/Target/TargetMachine.h"
39 using namespace llvm;
40 
41 #define DEBUG_TYPE "asm-printer"
42 
addInlineAsmDiagBuffer(StringRef AsmStr,const MDNode * LocMDNode) const43 unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr,
44                                             const MDNode *LocMDNode) const {
45   MCContext &Context = MMI->getContext();
46   Context.initInlineSourceManager();
47   SourceMgr &SrcMgr = *Context.getInlineSourceManager();
48   std::vector<const MDNode *> &LocInfos = Context.getLocInfos();
49 
50   std::unique_ptr<MemoryBuffer> Buffer;
51   // The inline asm source manager will outlive AsmStr, so make a copy of the
52   // string for SourceMgr to own.
53   Buffer = MemoryBuffer::getMemBufferCopy(AsmStr, "<inline asm>");
54 
55   // Tell SrcMgr about this buffer, it takes ownership of the buffer.
56   unsigned BufNum = SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
57 
58   // Store LocMDNode in DiagInfo, using BufNum as an identifier.
59   if (LocMDNode) {
60     LocInfos.resize(BufNum);
61     LocInfos[BufNum - 1] = LocMDNode;
62   }
63 
64   return BufNum;
65 }
66 
67 
68 /// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
emitInlineAsm(StringRef Str,const MCSubtargetInfo & STI,const MCTargetOptions & MCOptions,const MDNode * LocMDNode,InlineAsm::AsmDialect Dialect) const69 void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
70                                const MCTargetOptions &MCOptions,
71                                const MDNode *LocMDNode,
72                                InlineAsm::AsmDialect Dialect) const {
73   assert(!Str.empty() && "Can't emit empty inline asm block");
74 
75   // Remember if the buffer is nul terminated or not so we can avoid a copy.
76   bool isNullTerminated = Str.back() == 0;
77   if (isNullTerminated)
78     Str = Str.substr(0, Str.size()-1);
79 
80   // If the output streamer does not have mature MC support or the integrated
81   // assembler has been disabled, just emit the blob textually.
82   // Otherwise parse the asm and emit it via MC support.
83   // This is useful in case the asm parser doesn't handle something but the
84   // system assembler does.
85   const MCAsmInfo *MCAI = TM.getMCAsmInfo();
86   assert(MCAI && "No MCAsmInfo");
87   if (!MCAI->useIntegratedAssembler() &&
88       !OutStreamer->isIntegratedAssemblerRequired()) {
89     emitInlineAsmStart();
90     OutStreamer->emitRawText(Str);
91     emitInlineAsmEnd(STI, nullptr);
92     return;
93   }
94 
95   unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
96   SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
97   SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
98 
99   std::unique_ptr<MCAsmParser> Parser(
100       createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
101 
102   // Do not use assembler-level information for parsing inline assembly.
103   OutStreamer->setUseAssemblerInfoForParsing(false);
104 
105   // We create a new MCInstrInfo here since we might be at the module level
106   // and not have a MachineFunction to initialize the TargetInstrInfo from and
107   // we only need MCInstrInfo for asm parsing. We create one unconditionally
108   // because it's not subtarget dependent.
109   std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo());
110   assert(MII && "Failed to create instruction info");
111   std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
112       STI, *Parser, *MII, MCOptions));
113   if (!TAP)
114     report_fatal_error("Inline asm not supported by this streamer because"
115                        " we don't have an asm parser for this target\n");
116   Parser->setAssemblerDialect(Dialect);
117   Parser->setTargetParser(*TAP.get());
118   // Enable lexing Masm binary and hex integer literals in intel inline
119   // assembly.
120   if (Dialect == InlineAsm::AD_Intel)
121     Parser->getLexer().setLexMasmIntegers(true);
122 
123   emitInlineAsmStart();
124   // Don't implicitly switch to the text section before the asm.
125   (void)Parser->Run(/*NoInitialTextSection*/ true,
126                     /*NoFinalize*/ true);
127   emitInlineAsmEnd(STI, &TAP->getSTI());
128 }
129 
EmitMSInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)130 static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
131                                MachineModuleInfo *MMI, AsmPrinter *AP,
132                                unsigned LocCookie, raw_ostream &OS) {
133   // Switch to the inline assembly variant.
134   OS << "\t.intel_syntax\n\t";
135 
136   const char *LastEmitted = AsmStr; // One past the last character emitted.
137   unsigned NumOperands = MI->getNumOperands();
138 
139   while (*LastEmitted) {
140     switch (*LastEmitted) {
141     default: {
142       // Not a special case, emit the string section literally.
143       const char *LiteralEnd = LastEmitted+1;
144       while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
145              *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
146         ++LiteralEnd;
147 
148       OS.write(LastEmitted, LiteralEnd-LastEmitted);
149       LastEmitted = LiteralEnd;
150       break;
151     }
152     case '\n':
153       ++LastEmitted;   // Consume newline character.
154       OS << '\n';      // Indent code with newline.
155       break;
156     case '$': {
157       ++LastEmitted;   // Consume '$' character.
158       bool Done = true;
159 
160       // Handle escapes.
161       switch (*LastEmitted) {
162       default: Done = false; break;
163       case '$':
164         ++LastEmitted;  // Consume second '$' character.
165         break;
166       }
167       if (Done) break;
168 
169       bool HasCurlyBraces = false;
170       if (*LastEmitted == '{') {     // ${variable}
171         ++LastEmitted;               // Consume '{' character.
172         HasCurlyBraces = true;
173       }
174 
175       // If we have ${:foo}, then this is not a real operand reference, it is a
176       // "magic" string reference, just like in .td files.  Arrange to call
177       // PrintSpecial.
178       if (HasCurlyBraces && LastEmitted[0] == ':') {
179         ++LastEmitted;
180         const char *StrStart = LastEmitted;
181         const char *StrEnd = strchr(StrStart, '}');
182         if (!StrEnd)
183           report_fatal_error("Unterminated ${:foo} operand in inline asm"
184                              " string: '" + Twine(AsmStr) + "'");
185 
186         std::string Val(StrStart, StrEnd);
187         AP->PrintSpecial(MI, OS, Val.c_str());
188         LastEmitted = StrEnd+1;
189         break;
190       }
191 
192       const char *IDStart = LastEmitted;
193       const char *IDEnd = IDStart;
194       while (isDigit(*IDEnd))
195         ++IDEnd;
196 
197       unsigned Val;
198       if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
199         report_fatal_error("Bad $ operand number in inline asm string: '" +
200                            Twine(AsmStr) + "'");
201       LastEmitted = IDEnd;
202 
203       if (Val >= NumOperands-1)
204         report_fatal_error("Invalid $ operand number in inline asm string: '" +
205                            Twine(AsmStr) + "'");
206 
207       char Modifier[2] = { 0, 0 };
208 
209       if (HasCurlyBraces) {
210         // If we have curly braces, check for a modifier character.  This
211         // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
212         if (*LastEmitted == ':') {
213           ++LastEmitted;    // Consume ':' character.
214           if (*LastEmitted == 0)
215             report_fatal_error("Bad ${:} expression in inline asm string: '" +
216                                Twine(AsmStr) + "'");
217 
218           Modifier[0] = *LastEmitted;
219           ++LastEmitted;    // Consume modifier character.
220         }
221 
222         if (*LastEmitted != '}')
223           report_fatal_error("Bad ${} expression in inline asm string: '" +
224                              Twine(AsmStr) + "'");
225         ++LastEmitted;    // Consume '}' character.
226       }
227 
228       // Okay, we finally have a value number.  Ask the target to print this
229       // operand!
230       unsigned OpNo = InlineAsm::MIOp_FirstOperand;
231 
232       bool Error = false;
233 
234       // Scan to find the machine operand number for the operand.
235       for (; Val; --Val) {
236         if (OpNo >= MI->getNumOperands()) break;
237         unsigned OpFlags = MI->getOperand(OpNo).getImm();
238         OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
239       }
240 
241       // We may have a location metadata attached to the end of the
242       // instruction, and at no point should see metadata at any
243       // other point while processing. It's an error if so.
244       if (OpNo >= MI->getNumOperands() ||
245           MI->getOperand(OpNo).isMetadata()) {
246         Error = true;
247       } else {
248         unsigned OpFlags = MI->getOperand(OpNo).getImm();
249         ++OpNo;  // Skip over the ID number.
250 
251         if (InlineAsm::isMemKind(OpFlags)) {
252           Error = AP->PrintAsmMemoryOperand(
253               MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
254         } else {
255           Error = AP->PrintAsmOperand(MI, OpNo,
256                                       Modifier[0] ? Modifier : nullptr, OS);
257         }
258       }
259       if (Error) {
260         std::string msg;
261         raw_string_ostream Msg(msg);
262         Msg << "invalid operand in inline asm: '" << AsmStr << "'";
263         MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
264       }
265       break;
266     }
267     }
268   }
269   OS << "\n\t.att_syntax\n" << (char)0;  // null terminate string.
270 }
271 
EmitGCCInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,const MCAsmInfo * MAI,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)272 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
273                                 MachineModuleInfo *MMI, const MCAsmInfo *MAI,
274                                 AsmPrinter *AP, unsigned LocCookie,
275                                 raw_ostream &OS) {
276   int CurVariant = -1;            // The number of the {.|.|.} region we are in.
277   const char *LastEmitted = AsmStr; // One past the last character emitted.
278   unsigned NumOperands = MI->getNumOperands();
279   int AsmPrinterVariant = MAI->getAssemblerDialect();
280 
281   if (MAI->getEmitGNUAsmStartIndentationMarker())
282     OS << '\t';
283 
284   while (*LastEmitted) {
285     switch (*LastEmitted) {
286     default: {
287       // Not a special case, emit the string section literally.
288       const char *LiteralEnd = LastEmitted+1;
289       while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
290              *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
291         ++LiteralEnd;
292       if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
293         OS.write(LastEmitted, LiteralEnd-LastEmitted);
294       LastEmitted = LiteralEnd;
295       break;
296     }
297     case '\n':
298       ++LastEmitted;   // Consume newline character.
299       OS << '\n';      // Indent code with newline.
300       break;
301     case '$': {
302       ++LastEmitted;   // Consume '$' character.
303       bool Done = true;
304 
305       // Handle escapes.
306       switch (*LastEmitted) {
307       default: Done = false; break;
308       case '$':     // $$ -> $
309         if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
310           OS << '$';
311         ++LastEmitted;  // Consume second '$' character.
312         break;
313       case '(':             // $( -> same as GCC's { character.
314         ++LastEmitted;      // Consume '(' character.
315         if (CurVariant != -1)
316           report_fatal_error("Nested variants found in inline asm string: '" +
317                              Twine(AsmStr) + "'");
318         CurVariant = 0;     // We're in the first variant now.
319         break;
320       case '|':
321         ++LastEmitted;  // consume '|' character.
322         if (CurVariant == -1)
323           OS << '|';       // this is gcc's behavior for | outside a variant
324         else
325           ++CurVariant;   // We're in the next variant.
326         break;
327       case ')':         // $) -> same as GCC's } char.
328         ++LastEmitted;  // consume ')' character.
329         if (CurVariant == -1)
330           OS << '}';     // this is gcc's behavior for } outside a variant
331         else
332           CurVariant = -1;
333         break;
334       }
335       if (Done) break;
336 
337       bool HasCurlyBraces = false;
338       if (*LastEmitted == '{') {     // ${variable}
339         ++LastEmitted;               // Consume '{' character.
340         HasCurlyBraces = true;
341       }
342 
343       // If we have ${:foo}, then this is not a real operand reference, it is a
344       // "magic" string reference, just like in .td files.  Arrange to call
345       // PrintSpecial.
346       if (HasCurlyBraces && *LastEmitted == ':') {
347         ++LastEmitted;
348         const char *StrStart = LastEmitted;
349         const char *StrEnd = strchr(StrStart, '}');
350         if (!StrEnd)
351           report_fatal_error("Unterminated ${:foo} operand in inline asm"
352                              " string: '" + Twine(AsmStr) + "'");
353 
354         std::string Val(StrStart, StrEnd);
355         AP->PrintSpecial(MI, OS, Val.c_str());
356         LastEmitted = StrEnd+1;
357         break;
358       }
359 
360       const char *IDStart = LastEmitted;
361       const char *IDEnd = IDStart;
362       while (isDigit(*IDEnd))
363         ++IDEnd;
364 
365       unsigned Val;
366       if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
367         report_fatal_error("Bad $ operand number in inline asm string: '" +
368                            Twine(AsmStr) + "'");
369       LastEmitted = IDEnd;
370 
371       char Modifier[2] = { 0, 0 };
372 
373       if (HasCurlyBraces) {
374         // If we have curly braces, check for a modifier character.  This
375         // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
376         if (*LastEmitted == ':') {
377           ++LastEmitted;    // Consume ':' character.
378           if (*LastEmitted == 0)
379             report_fatal_error("Bad ${:} expression in inline asm string: '" +
380                                Twine(AsmStr) + "'");
381 
382           Modifier[0] = *LastEmitted;
383           ++LastEmitted;    // Consume modifier character.
384         }
385 
386         if (*LastEmitted != '}')
387           report_fatal_error("Bad ${} expression in inline asm string: '" +
388                              Twine(AsmStr) + "'");
389         ++LastEmitted;    // Consume '}' character.
390       }
391 
392       if (Val >= NumOperands-1)
393         report_fatal_error("Invalid $ operand number in inline asm string: '" +
394                            Twine(AsmStr) + "'");
395 
396       // Okay, we finally have a value number.  Ask the target to print this
397       // operand!
398       if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
399         unsigned OpNo = InlineAsm::MIOp_FirstOperand;
400 
401         bool Error = false;
402 
403         // Scan to find the machine operand number for the operand.
404         for (; Val; --Val) {
405           if (OpNo >= MI->getNumOperands()) break;
406           unsigned OpFlags = MI->getOperand(OpNo).getImm();
407           OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
408         }
409 
410         // We may have a location metadata attached to the end of the
411         // instruction, and at no point should see metadata at any
412         // other point while processing. It's an error if so.
413         if (OpNo >= MI->getNumOperands() ||
414             MI->getOperand(OpNo).isMetadata()) {
415           Error = true;
416         } else {
417           unsigned OpFlags = MI->getOperand(OpNo).getImm();
418           ++OpNo;  // Skip over the ID number.
419 
420           // FIXME: Shouldn't arch-independent output template handling go into
421           // PrintAsmOperand?
422           // Labels are target independent.
423           if (MI->getOperand(OpNo).isBlockAddress()) {
424             const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
425             MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
426             Sym->print(OS, AP->MAI);
427             MMI->getContext().registerInlineAsmLabel(Sym);
428           } else if (MI->getOperand(OpNo).isMBB()) {
429             const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
430             Sym->print(OS, AP->MAI);
431           } else if (Modifier[0] == 'l') {
432             Error = true;
433           } else if (InlineAsm::isMemKind(OpFlags)) {
434             Error = AP->PrintAsmMemoryOperand(
435                 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
436           } else {
437             Error = AP->PrintAsmOperand(MI, OpNo,
438                                         Modifier[0] ? Modifier : nullptr, OS);
439           }
440         }
441         if (Error) {
442           std::string msg;
443           raw_string_ostream Msg(msg);
444           Msg << "invalid operand in inline asm: '" << AsmStr << "'";
445           MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
446         }
447       }
448       break;
449     }
450     }
451   }
452   OS << '\n' << (char)0;  // null terminate string.
453 }
454 
455 /// This method formats and emits the specified machine instruction that is an
456 /// inline asm.
emitInlineAsm(const MachineInstr * MI) const457 void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
458   assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
459 
460   // Count the number of register definitions to find the asm string.
461   unsigned NumDefs = 0;
462   for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
463        ++NumDefs)
464     assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
465 
466   assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
467 
468   // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
469   const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
470 
471   // If this asmstr is empty, just print the #APP/#NOAPP markers.
472   // These are useful to see where empty asm's wound up.
473   if (AsmStr[0] == 0) {
474     OutStreamer->emitRawComment(MAI->getInlineAsmStart());
475     OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
476     return;
477   }
478 
479   // Emit the #APP start marker.  This has to happen even if verbose-asm isn't
480   // enabled, so we use emitRawComment.
481   OutStreamer->emitRawComment(MAI->getInlineAsmStart());
482 
483   // Get the !srcloc metadata node if we have it, and decode the loc cookie from
484   // it.
485   unsigned LocCookie = 0;
486   const MDNode *LocMD = nullptr;
487   for (unsigned i = MI->getNumOperands(); i != 0; --i) {
488     if (MI->getOperand(i-1).isMetadata() &&
489         (LocMD = MI->getOperand(i-1).getMetadata()) &&
490         LocMD->getNumOperands() != 0) {
491       if (const ConstantInt *CI =
492               mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
493         LocCookie = CI->getZExtValue();
494         break;
495       }
496     }
497   }
498 
499   // Emit the inline asm to a temporary string so we can emit it through
500   // EmitInlineAsm.
501   SmallString<256> StringData;
502   raw_svector_ostream OS(StringData);
503 
504   AsmPrinter *AP = const_cast<AsmPrinter*>(this);
505   if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
506     EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
507   else
508     EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS);
509 
510   // Emit warnings if we use reserved registers on the clobber list, as
511   // that might lead to undefined behaviour.
512   SmallVector<Register, 8> RestrRegs;
513   const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
514   // Start with the first operand descriptor, and iterate over them.
515   for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands();
516        I < NumOps; ++I) {
517     const MachineOperand &MO = MI->getOperand(I);
518     if (!MO.isImm())
519       continue;
520     unsigned Flags = MO.getImm();
521     if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) {
522       Register Reg = MI->getOperand(I + 1).getReg();
523       if (!TRI->isAsmClobberable(*MF, Reg))
524         RestrRegs.push_back(Reg);
525     }
526     // Skip to one before the next operand descriptor, if it exists.
527     I += InlineAsm::getNumOperandRegisters(Flags);
528   }
529 
530   if (!RestrRegs.empty()) {
531     std::string Msg = "inline asm clobber list contains reserved registers: ";
532     ListSeparator LS;
533     for (const Register &RR : RestrRegs) {
534       Msg += LS;
535       Msg += TRI->getName(RR);
536     }
537     const char *Note =
538         "Reserved registers on the clobber list may not be "
539         "preserved across the asm statement, and clobbering them may "
540         "lead to undefined behaviour.";
541     MMI->getModule()->getContext().diagnose(DiagnosticInfoInlineAsm(
542         LocCookie, Msg.c_str(), DiagnosticSeverity::DS_Warning));
543     MMI->getModule()->getContext().diagnose(
544         DiagnosticInfoInlineAsm(LocCookie, Note, DiagnosticSeverity::DS_Note));
545   }
546 
547   emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD,
548                 MI->getInlineAsmDialect());
549 
550   // Emit the #NOAPP end marker.  This has to happen even if verbose-asm isn't
551   // enabled, so we use emitRawComment.
552   OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
553 }
554 
555 /// PrintSpecial - Print information related to the specified machine instr
556 /// that is independent of the operand, and may be independent of the instr
557 /// itself.  This can be useful for portably encoding the comment character
558 /// or other bits of target-specific knowledge into the asmstrings.  The
559 /// syntax used is ${:comment}.  Targets can override this to add support
560 /// for their own strange codes.
PrintSpecial(const MachineInstr * MI,raw_ostream & OS,const char * Code) const561 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
562                               const char *Code) const {
563   if (!strcmp(Code, "private")) {
564     const DataLayout &DL = MF->getDataLayout();
565     OS << DL.getPrivateGlobalPrefix();
566   } else if (!strcmp(Code, "comment")) {
567     OS << MAI->getCommentString();
568   } else if (!strcmp(Code, "uid")) {
569     // Comparing the address of MI isn't sufficient, because machineinstrs may
570     // be allocated to the same address across functions.
571 
572     // If this is a new LastFn instruction, bump the counter.
573     if (LastMI != MI || LastFn != getFunctionNumber()) {
574       ++Counter;
575       LastMI = MI;
576       LastFn = getFunctionNumber();
577     }
578     OS << Counter;
579   } else {
580     std::string msg;
581     raw_string_ostream Msg(msg);
582     Msg << "Unknown special formatter '" << Code
583          << "' for machine instr: " << *MI;
584     report_fatal_error(Msg.str());
585   }
586 }
587 
PrintSymbolOperand(const MachineOperand & MO,raw_ostream & OS)588 void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) {
589   assert(MO.isGlobal() && "caller should check MO.isGlobal");
590   getSymbolPreferLocal(*MO.getGlobal())->print(OS, MAI);
591   printOffset(MO.getOffset(), OS);
592 }
593 
594 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
595 /// instruction, using the specified assembler variant.  Targets should
596 /// override this to format as appropriate for machine specific ExtraCodes
597 /// or when the arch-independent handling would be too complex otherwise.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)598 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
599                                  const char *ExtraCode, raw_ostream &O) {
600   // Does this asm operand have a single letter operand modifier?
601   if (ExtraCode && ExtraCode[0]) {
602     if (ExtraCode[1] != 0) return true; // Unknown modifier.
603 
604     // https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html
605     const MachineOperand &MO = MI->getOperand(OpNo);
606     switch (ExtraCode[0]) {
607     default:
608       return true;  // Unknown modifier.
609     case 'a': // Print as memory address.
610       if (MO.isReg()) {
611         PrintAsmMemoryOperand(MI, OpNo, nullptr, O);
612         return false;
613       }
614       LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates.
615     case 'c': // Substitute immediate value without immediate syntax
616       if (MO.isImm()) {
617         O << MO.getImm();
618         return false;
619       }
620       if (MO.isGlobal()) {
621         PrintSymbolOperand(MO, O);
622         return false;
623       }
624       return true;
625     case 'n':  // Negate the immediate constant.
626       if (!MO.isImm())
627         return true;
628       O << -MO.getImm();
629       return false;
630     case 's':  // The GCC deprecated s modifier
631       if (!MO.isImm())
632         return true;
633       O << ((32 - MO.getImm()) & 31);
634       return false;
635     }
636   }
637   return true;
638 }
639 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)640 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
641                                        const char *ExtraCode, raw_ostream &O) {
642   // Target doesn't support this yet!
643   return true;
644 }
645 
emitInlineAsmStart() const646 void AsmPrinter::emitInlineAsmStart() const {}
647 
emitInlineAsmEnd(const MCSubtargetInfo & StartInfo,const MCSubtargetInfo * EndInfo) const648 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
649                                   const MCSubtargetInfo *EndInfo) const {}
650