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 
43 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.
69 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 
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 
272 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
273                                 MachineModuleInfo *MMI, int AsmPrinterVariant,
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 
280   OS << '\t';
281 
282   while (*LastEmitted) {
283     switch (*LastEmitted) {
284     default: {
285       // Not a special case, emit the string section literally.
286       const char *LiteralEnd = LastEmitted+1;
287       while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
288              *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
289         ++LiteralEnd;
290       if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
291         OS.write(LastEmitted, LiteralEnd-LastEmitted);
292       LastEmitted = LiteralEnd;
293       break;
294     }
295     case '\n':
296       ++LastEmitted;   // Consume newline character.
297       OS << '\n';      // Indent code with newline.
298       break;
299     case '$': {
300       ++LastEmitted;   // Consume '$' character.
301       bool Done = true;
302 
303       // Handle escapes.
304       switch (*LastEmitted) {
305       default: Done = false; break;
306       case '$':     // $$ -> $
307         if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
308           OS << '$';
309         ++LastEmitted;  // Consume second '$' character.
310         break;
311       case '(':             // $( -> same as GCC's { character.
312         ++LastEmitted;      // Consume '(' character.
313         if (CurVariant != -1)
314           report_fatal_error("Nested variants found in inline asm string: '" +
315                              Twine(AsmStr) + "'");
316         CurVariant = 0;     // We're in the first variant now.
317         break;
318       case '|':
319         ++LastEmitted;  // consume '|' character.
320         if (CurVariant == -1)
321           OS << '|';       // this is gcc's behavior for | outside a variant
322         else
323           ++CurVariant;   // We're in the next variant.
324         break;
325       case ')':         // $) -> same as GCC's } char.
326         ++LastEmitted;  // consume ')' character.
327         if (CurVariant == -1)
328           OS << '}';     // this is gcc's behavior for } outside a variant
329         else
330           CurVariant = -1;
331         break;
332       }
333       if (Done) break;
334 
335       bool HasCurlyBraces = false;
336       if (*LastEmitted == '{') {     // ${variable}
337         ++LastEmitted;               // Consume '{' character.
338         HasCurlyBraces = true;
339       }
340 
341       // If we have ${:foo}, then this is not a real operand reference, it is a
342       // "magic" string reference, just like in .td files.  Arrange to call
343       // PrintSpecial.
344       if (HasCurlyBraces && *LastEmitted == ':') {
345         ++LastEmitted;
346         const char *StrStart = LastEmitted;
347         const char *StrEnd = strchr(StrStart, '}');
348         if (!StrEnd)
349           report_fatal_error("Unterminated ${:foo} operand in inline asm"
350                              " string: '" + Twine(AsmStr) + "'");
351 
352         std::string Val(StrStart, StrEnd);
353         AP->PrintSpecial(MI, OS, Val.c_str());
354         LastEmitted = StrEnd+1;
355         break;
356       }
357 
358       const char *IDStart = LastEmitted;
359       const char *IDEnd = IDStart;
360       while (isDigit(*IDEnd))
361         ++IDEnd;
362 
363       unsigned Val;
364       if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
365         report_fatal_error("Bad $ operand number in inline asm string: '" +
366                            Twine(AsmStr) + "'");
367       LastEmitted = IDEnd;
368 
369       char Modifier[2] = { 0, 0 };
370 
371       if (HasCurlyBraces) {
372         // If we have curly braces, check for a modifier character.  This
373         // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
374         if (*LastEmitted == ':') {
375           ++LastEmitted;    // Consume ':' character.
376           if (*LastEmitted == 0)
377             report_fatal_error("Bad ${:} expression in inline asm string: '" +
378                                Twine(AsmStr) + "'");
379 
380           Modifier[0] = *LastEmitted;
381           ++LastEmitted;    // Consume modifier character.
382         }
383 
384         if (*LastEmitted != '}')
385           report_fatal_error("Bad ${} expression in inline asm string: '" +
386                              Twine(AsmStr) + "'");
387         ++LastEmitted;    // Consume '}' character.
388       }
389 
390       if (Val >= NumOperands-1)
391         report_fatal_error("Invalid $ operand number in inline asm string: '" +
392                            Twine(AsmStr) + "'");
393 
394       // Okay, we finally have a value number.  Ask the target to print this
395       // operand!
396       if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
397         unsigned OpNo = InlineAsm::MIOp_FirstOperand;
398 
399         bool Error = false;
400 
401         // Scan to find the machine operand number for the operand.
402         for (; Val; --Val) {
403           if (OpNo >= MI->getNumOperands()) break;
404           unsigned OpFlags = MI->getOperand(OpNo).getImm();
405           OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
406         }
407 
408         // We may have a location metadata attached to the end of the
409         // instruction, and at no point should see metadata at any
410         // other point while processing. It's an error if so.
411         if (OpNo >= MI->getNumOperands() ||
412             MI->getOperand(OpNo).isMetadata()) {
413           Error = true;
414         } else {
415           unsigned OpFlags = MI->getOperand(OpNo).getImm();
416           ++OpNo;  // Skip over the ID number.
417 
418           // FIXME: Shouldn't arch-independent output template handling go into
419           // PrintAsmOperand?
420           // Labels are target independent.
421           if (MI->getOperand(OpNo).isBlockAddress()) {
422             const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
423             MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
424             Sym->print(OS, AP->MAI);
425             MMI->getContext().registerInlineAsmLabel(Sym);
426           } else if (MI->getOperand(OpNo).isMBB()) {
427             const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
428             Sym->print(OS, AP->MAI);
429           } else if (Modifier[0] == 'l') {
430             Error = true;
431           } else if (InlineAsm::isMemKind(OpFlags)) {
432             Error = AP->PrintAsmMemoryOperand(
433                 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
434           } else {
435             Error = AP->PrintAsmOperand(MI, OpNo,
436                                         Modifier[0] ? Modifier : nullptr, OS);
437           }
438         }
439         if (Error) {
440           std::string msg;
441           raw_string_ostream Msg(msg);
442           Msg << "invalid operand in inline asm: '" << AsmStr << "'";
443           MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
444         }
445       }
446       break;
447     }
448     }
449   }
450   OS << '\n' << (char)0;  // null terminate string.
451 }
452 
453 /// This method formats and emits the specified machine instruction that is an
454 /// inline asm.
455 void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
456   assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
457 
458   // Count the number of register definitions to find the asm string.
459   unsigned NumDefs = 0;
460   for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
461        ++NumDefs)
462     assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
463 
464   assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
465 
466   // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
467   const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
468 
469   // If this asmstr is empty, just print the #APP/#NOAPP markers.
470   // These are useful to see where empty asm's wound up.
471   if (AsmStr[0] == 0) {
472     OutStreamer->emitRawComment(MAI->getInlineAsmStart());
473     OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
474     return;
475   }
476 
477   // Emit the #APP start marker.  This has to happen even if verbose-asm isn't
478   // enabled, so we use emitRawComment.
479   OutStreamer->emitRawComment(MAI->getInlineAsmStart());
480 
481   // Get the !srcloc metadata node if we have it, and decode the loc cookie from
482   // it.
483   unsigned LocCookie = 0;
484   const MDNode *LocMD = nullptr;
485   for (unsigned i = MI->getNumOperands(); i != 0; --i) {
486     if (MI->getOperand(i-1).isMetadata() &&
487         (LocMD = MI->getOperand(i-1).getMetadata()) &&
488         LocMD->getNumOperands() != 0) {
489       if (const ConstantInt *CI =
490               mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
491         LocCookie = CI->getZExtValue();
492         break;
493       }
494     }
495   }
496 
497   // Emit the inline asm to a temporary string so we can emit it through
498   // EmitInlineAsm.
499   SmallString<256> StringData;
500   raw_svector_ostream OS(StringData);
501 
502   // The variant of the current asmprinter.
503   int AsmPrinterVariant = MAI->getAssemblerDialect();
504   AsmPrinter *AP = const_cast<AsmPrinter*>(this);
505   if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
506     EmitGCCInlineAsmStr(AsmStr, MI, MMI, AsmPrinterVariant, 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.
561 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 
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.
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 
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 
646 void AsmPrinter::emitInlineAsmStart() const {}
647 
648 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
649                                   const MCSubtargetInfo *EndInfo) const {}
650