• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
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 // This file implements the inline assembler pieces of the AsmPrinter class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/CodeGen/AsmPrinter.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/CodeGen/MachineBasicBlock.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/CodeGen/MachineModuleInfo.h"
20 #include "llvm/IR/Constants.h"
21 #include "llvm/IR/DataLayout.h"
22 #include "llvm/IR/InlineAsm.h"
23 #include "llvm/IR/LLVMContext.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/MC/MCAsmInfo.h"
26 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSubtargetInfo.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/MemoryBuffer.h"
32 #include "llvm/Support/SourceMgr.h"
33 #include "llvm/Support/TargetRegistry.h"
34 #include "llvm/Support/raw_ostream.h"
35 #include "llvm/Target/TargetInstrInfo.h"
36 #include "llvm/Target/TargetMachine.h"
37 #include "llvm/Target/TargetRegisterInfo.h"
38 #include "llvm/Target/TargetSubtargetInfo.h"
39 using namespace llvm;
40 
41 #define DEBUG_TYPE "asm-printer"
42 
43 namespace {
44   struct SrcMgrDiagInfo {
45     const MDNode *LocInfo;
46     LLVMContext::InlineAsmDiagHandlerTy DiagHandler;
47     void *DiagContext;
48   };
49 }
50 
51 /// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an
52 /// inline asm has an error in it.  diagInfo is a pointer to the SrcMgrDiagInfo
53 /// struct above.
srcMgrDiagHandler(const SMDiagnostic & Diag,void * diagInfo)54 static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) {
55   SrcMgrDiagInfo *DiagInfo = static_cast<SrcMgrDiagInfo *>(diagInfo);
56   assert(DiagInfo && "Diagnostic context not passed down?");
57 
58   // If the inline asm had metadata associated with it, pull out a location
59   // cookie corresponding to which line the error occurred on.
60   unsigned LocCookie = 0;
61   if (const MDNode *LocInfo = DiagInfo->LocInfo) {
62     unsigned ErrorLine = Diag.getLineNo()-1;
63     if (ErrorLine >= LocInfo->getNumOperands())
64       ErrorLine = 0;
65 
66     if (LocInfo->getNumOperands() != 0)
67       if (const ConstantInt *CI =
68               mdconst::dyn_extract<ConstantInt>(LocInfo->getOperand(ErrorLine)))
69         LocCookie = CI->getZExtValue();
70   }
71 
72   DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie);
73 }
74 
75 /// 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) const76 void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
77                                const MCTargetOptions &MCOptions,
78                                const MDNode *LocMDNode,
79                                InlineAsm::AsmDialect Dialect) const {
80   assert(!Str.empty() && "Can't emit empty inline asm block");
81 
82   // Remember if the buffer is nul terminated or not so we can avoid a copy.
83   bool isNullTerminated = Str.back() == 0;
84   if (isNullTerminated)
85     Str = Str.substr(0, Str.size()-1);
86 
87   // If the output streamer does not have mature MC support or the integrated
88   // assembler has been disabled, just emit the blob textually.
89   // Otherwise parse the asm and emit it via MC support.
90   // This is useful in case the asm parser doesn't handle something but the
91   // system assembler does.
92   const MCAsmInfo *MCAI = TM.getMCAsmInfo();
93   assert(MCAI && "No MCAsmInfo");
94   if (!MCAI->useIntegratedAssembler() &&
95       !OutStreamer->isIntegratedAssemblerRequired()) {
96     emitInlineAsmStart();
97     OutStreamer->EmitRawText(Str);
98     emitInlineAsmEnd(STI, nullptr);
99     return;
100   }
101 
102   SourceMgr SrcMgr;
103   SrcMgrDiagInfo DiagInfo;
104 
105   // If the current LLVMContext has an inline asm handler, set it in SourceMgr.
106   LLVMContext &LLVMCtx = MMI->getModule()->getContext();
107   bool HasDiagHandler = false;
108   if (LLVMCtx.getInlineAsmDiagnosticHandler() != nullptr) {
109     // If the source manager has an issue, we arrange for srcMgrDiagHandler
110     // to be invoked, getting DiagInfo passed into it.
111     DiagInfo.LocInfo = LocMDNode;
112     DiagInfo.DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler();
113     DiagInfo.DiagContext = LLVMCtx.getInlineAsmDiagnosticContext();
114     SrcMgr.setDiagHandler(srcMgrDiagHandler, &DiagInfo);
115     HasDiagHandler = true;
116   }
117 
118   std::unique_ptr<MemoryBuffer> Buffer;
119   if (isNullTerminated)
120     Buffer = MemoryBuffer::getMemBuffer(Str, "<inline asm>");
121   else
122     Buffer = MemoryBuffer::getMemBufferCopy(Str, "<inline asm>");
123 
124   // Tell SrcMgr about this buffer, it takes ownership of the buffer.
125   SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
126 
127   std::unique_ptr<MCAsmParser> Parser(
128       createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI));
129 
130   // We create a new MCInstrInfo here since we might be at the module level
131   // and not have a MachineFunction to initialize the TargetInstrInfo from and
132   // we only need MCInstrInfo for asm parsing. We create one unconditionally
133   // because it's not subtarget dependent.
134   std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo());
135   std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
136       STI, *Parser, *MII, MCOptions));
137   if (!TAP)
138     report_fatal_error("Inline asm not supported by this streamer because"
139                        " we don't have an asm parser for this target\n");
140   Parser->setAssemblerDialect(Dialect);
141   Parser->setTargetParser(*TAP.get());
142   if (MF) {
143     const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
144     TAP->SetFrameRegister(TRI->getFrameRegister(*MF));
145   }
146 
147   emitInlineAsmStart();
148   // Don't implicitly switch to the text section before the asm.
149   int Res = Parser->Run(/*NoInitialTextSection*/ true,
150                         /*NoFinalize*/ true);
151   emitInlineAsmEnd(STI, &TAP->getSTI());
152   if (Res && !HasDiagHandler)
153     report_fatal_error("Error parsing inline asm\n");
154 }
155 
EmitMSInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,int InlineAsmVariant,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)156 static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
157                                MachineModuleInfo *MMI, int InlineAsmVariant,
158                                AsmPrinter *AP, unsigned LocCookie,
159                                raw_ostream &OS) {
160   // Switch to the inline assembly variant.
161   OS << "\t.intel_syntax\n\t";
162 
163   const char *LastEmitted = AsmStr; // One past the last character emitted.
164   unsigned NumOperands = MI->getNumOperands();
165 
166   while (*LastEmitted) {
167     switch (*LastEmitted) {
168     default: {
169       // Not a special case, emit the string section literally.
170       const char *LiteralEnd = LastEmitted+1;
171       while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
172              *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
173         ++LiteralEnd;
174 
175       OS.write(LastEmitted, LiteralEnd-LastEmitted);
176       LastEmitted = LiteralEnd;
177       break;
178     }
179     case '\n':
180       ++LastEmitted;   // Consume newline character.
181       OS << '\n';      // Indent code with newline.
182       break;
183     case '$': {
184       ++LastEmitted;   // Consume '$' character.
185       bool Done = true;
186 
187       // Handle escapes.
188       switch (*LastEmitted) {
189       default: Done = false; break;
190       case '$':
191         ++LastEmitted;  // Consume second '$' character.
192         break;
193       }
194       if (Done) break;
195 
196       const char *IDStart = LastEmitted;
197       const char *IDEnd = IDStart;
198       while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd;
199 
200       unsigned Val;
201       if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
202         report_fatal_error("Bad $ operand number in inline asm string: '" +
203                            Twine(AsmStr) + "'");
204       LastEmitted = IDEnd;
205 
206       if (Val >= NumOperands-1)
207         report_fatal_error("Invalid $ operand number in inline asm string: '" +
208                            Twine(AsmStr) + "'");
209 
210       // Okay, we finally have a value number.  Ask the target to print this
211       // operand!
212       unsigned OpNo = InlineAsm::MIOp_FirstOperand;
213 
214       bool Error = false;
215 
216       // Scan to find the machine operand number for the operand.
217       for (; Val; --Val) {
218         if (OpNo >= MI->getNumOperands()) break;
219         unsigned OpFlags = MI->getOperand(OpNo).getImm();
220         OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
221       }
222 
223       // We may have a location metadata attached to the end of the
224       // instruction, and at no point should see metadata at any
225       // other point while processing. It's an error if so.
226       if (OpNo >= MI->getNumOperands() ||
227           MI->getOperand(OpNo).isMetadata()) {
228         Error = true;
229       } else {
230         unsigned OpFlags = MI->getOperand(OpNo).getImm();
231         ++OpNo;  // Skip over the ID number.
232 
233         if (InlineAsm::isMemKind(OpFlags)) {
234           Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant,
235                                             /*Modifier*/ nullptr, OS);
236         } else {
237           Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant,
238                                       /*Modifier*/ nullptr, OS);
239         }
240       }
241       if (Error) {
242         std::string msg;
243         raw_string_ostream Msg(msg);
244         Msg << "invalid operand in inline asm: '" << AsmStr << "'";
245         MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
246       }
247       break;
248     }
249     }
250   }
251   OS << "\n\t.att_syntax\n" << (char)0;  // null terminate string.
252 }
253 
EmitGCCInlineAsmStr(const char * AsmStr,const MachineInstr * MI,MachineModuleInfo * MMI,int InlineAsmVariant,int AsmPrinterVariant,AsmPrinter * AP,unsigned LocCookie,raw_ostream & OS)254 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
255                                 MachineModuleInfo *MMI, int InlineAsmVariant,
256                                 int AsmPrinterVariant, AsmPrinter *AP,
257                                 unsigned LocCookie, raw_ostream &OS) {
258   int CurVariant = -1;            // The number of the {.|.|.} region we are in.
259   const char *LastEmitted = AsmStr; // One past the last character emitted.
260   unsigned NumOperands = MI->getNumOperands();
261 
262   OS << '\t';
263 
264   while (*LastEmitted) {
265     switch (*LastEmitted) {
266     default: {
267       // Not a special case, emit the string section literally.
268       const char *LiteralEnd = LastEmitted+1;
269       while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
270              *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
271         ++LiteralEnd;
272       if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
273         OS.write(LastEmitted, LiteralEnd-LastEmitted);
274       LastEmitted = LiteralEnd;
275       break;
276     }
277     case '\n':
278       ++LastEmitted;   // Consume newline character.
279       OS << '\n';      // Indent code with newline.
280       break;
281     case '$': {
282       ++LastEmitted;   // Consume '$' character.
283       bool Done = true;
284 
285       // Handle escapes.
286       switch (*LastEmitted) {
287       default: Done = false; break;
288       case '$':     // $$ -> $
289         if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
290           OS << '$';
291         ++LastEmitted;  // Consume second '$' character.
292         break;
293       case '(':             // $( -> same as GCC's { character.
294         ++LastEmitted;      // Consume '(' character.
295         if (CurVariant != -1)
296           report_fatal_error("Nested variants found in inline asm string: '" +
297                              Twine(AsmStr) + "'");
298         CurVariant = 0;     // We're in the first variant now.
299         break;
300       case '|':
301         ++LastEmitted;  // consume '|' character.
302         if (CurVariant == -1)
303           OS << '|';       // this is gcc's behavior for | outside a variant
304         else
305           ++CurVariant;   // We're in the next variant.
306         break;
307       case ')':         // $) -> same as GCC's } char.
308         ++LastEmitted;  // consume ')' character.
309         if (CurVariant == -1)
310           OS << '}';     // this is gcc's behavior for } outside a variant
311         else
312           CurVariant = -1;
313         break;
314       }
315       if (Done) break;
316 
317       bool HasCurlyBraces = false;
318       if (*LastEmitted == '{') {     // ${variable}
319         ++LastEmitted;               // Consume '{' character.
320         HasCurlyBraces = true;
321       }
322 
323       // If we have ${:foo}, then this is not a real operand reference, it is a
324       // "magic" string reference, just like in .td files.  Arrange to call
325       // PrintSpecial.
326       if (HasCurlyBraces && *LastEmitted == ':') {
327         ++LastEmitted;
328         const char *StrStart = LastEmitted;
329         const char *StrEnd = strchr(StrStart, '}');
330         if (!StrEnd)
331           report_fatal_error("Unterminated ${:foo} operand in inline asm"
332                              " string: '" + Twine(AsmStr) + "'");
333 
334         std::string Val(StrStart, StrEnd);
335         AP->PrintSpecial(MI, OS, Val.c_str());
336         LastEmitted = StrEnd+1;
337         break;
338       }
339 
340       const char *IDStart = LastEmitted;
341       const char *IDEnd = IDStart;
342       while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd;
343 
344       unsigned Val;
345       if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
346         report_fatal_error("Bad $ operand number in inline asm string: '" +
347                            Twine(AsmStr) + "'");
348       LastEmitted = IDEnd;
349 
350       char Modifier[2] = { 0, 0 };
351 
352       if (HasCurlyBraces) {
353         // If we have curly braces, check for a modifier character.  This
354         // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
355         if (*LastEmitted == ':') {
356           ++LastEmitted;    // Consume ':' character.
357           if (*LastEmitted == 0)
358             report_fatal_error("Bad ${:} expression in inline asm string: '" +
359                                Twine(AsmStr) + "'");
360 
361           Modifier[0] = *LastEmitted;
362           ++LastEmitted;    // Consume modifier character.
363         }
364 
365         if (*LastEmitted != '}')
366           report_fatal_error("Bad ${} expression in inline asm string: '" +
367                              Twine(AsmStr) + "'");
368         ++LastEmitted;    // Consume '}' character.
369       }
370 
371       if (Val >= NumOperands-1)
372         report_fatal_error("Invalid $ operand number in inline asm string: '" +
373                            Twine(AsmStr) + "'");
374 
375       // Okay, we finally have a value number.  Ask the target to print this
376       // operand!
377       if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
378         unsigned OpNo = InlineAsm::MIOp_FirstOperand;
379 
380         bool Error = false;
381 
382         // Scan to find the machine operand number for the operand.
383         for (; Val; --Val) {
384           if (OpNo >= MI->getNumOperands()) break;
385           unsigned OpFlags = MI->getOperand(OpNo).getImm();
386           OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
387         }
388 
389         // We may have a location metadata attached to the end of the
390         // instruction, and at no point should see metadata at any
391         // other point while processing. It's an error if so.
392         if (OpNo >= MI->getNumOperands() ||
393             MI->getOperand(OpNo).isMetadata()) {
394           Error = true;
395         } else {
396           unsigned OpFlags = MI->getOperand(OpNo).getImm();
397           ++OpNo;  // Skip over the ID number.
398 
399           if (Modifier[0] == 'l') { // Labels are target independent.
400             // FIXME: What if the operand isn't an MBB, report error?
401             const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
402             Sym->print(OS, AP->MAI);
403           } else {
404             if (InlineAsm::isMemKind(OpFlags)) {
405               Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant,
406                                                 Modifier[0] ? Modifier : nullptr,
407                                                 OS);
408             } else {
409               Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant,
410                                           Modifier[0] ? Modifier : nullptr, OS);
411             }
412           }
413         }
414         if (Error) {
415           std::string msg;
416           raw_string_ostream Msg(msg);
417           Msg << "invalid operand in inline asm: '" << AsmStr << "'";
418           MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
419         }
420       }
421       break;
422     }
423     }
424   }
425   OS << '\n' << (char)0;  // null terminate string.
426 }
427 
428 /// EmitInlineAsm - This method formats and emits the specified machine
429 /// instruction that is an inline asm.
EmitInlineAsm(const MachineInstr * MI) const430 void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const {
431   assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
432 
433   // Count the number of register definitions to find the asm string.
434   unsigned NumDefs = 0;
435   for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
436        ++NumDefs)
437     assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
438 
439   assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
440 
441   // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
442   const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
443 
444   // If this asmstr is empty, just print the #APP/#NOAPP markers.
445   // These are useful to see where empty asm's wound up.
446   if (AsmStr[0] == 0) {
447     OutStreamer->emitRawComment(MAI->getInlineAsmStart());
448     OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
449     return;
450   }
451 
452   // Emit the #APP start marker.  This has to happen even if verbose-asm isn't
453   // enabled, so we use emitRawComment.
454   OutStreamer->emitRawComment(MAI->getInlineAsmStart());
455 
456   // Get the !srcloc metadata node if we have it, and decode the loc cookie from
457   // it.
458   unsigned LocCookie = 0;
459   const MDNode *LocMD = nullptr;
460   for (unsigned i = MI->getNumOperands(); i != 0; --i) {
461     if (MI->getOperand(i-1).isMetadata() &&
462         (LocMD = MI->getOperand(i-1).getMetadata()) &&
463         LocMD->getNumOperands() != 0) {
464       if (const ConstantInt *CI =
465               mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
466         LocCookie = CI->getZExtValue();
467         break;
468       }
469     }
470   }
471 
472   // Emit the inline asm to a temporary string so we can emit it through
473   // EmitInlineAsm.
474   SmallString<256> StringData;
475   raw_svector_ostream OS(StringData);
476 
477   // The variant of the current asmprinter.
478   int AsmPrinterVariant = MAI->getAssemblerDialect();
479   InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect();
480   AsmPrinter *AP = const_cast<AsmPrinter*>(this);
481   if (InlineAsmVariant == InlineAsm::AD_ATT)
482     EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant,
483                         AP, LocCookie, OS);
484   else
485     EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS);
486 
487   // Reset SanitizeAddress based on the function's attribute.
488   MCTargetOptions MCOptions = TM.Options.MCOptions;
489   MCOptions.SanitizeAddress =
490       MF->getFunction()->hasFnAttribute(Attribute::SanitizeAddress);
491 
492   EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD,
493                 MI->getInlineAsmDialect());
494 
495   // Emit the #NOAPP end marker.  This has to happen even if verbose-asm isn't
496   // enabled, so we use emitRawComment.
497   OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
498 }
499 
500 
501 /// PrintSpecial - Print information related to the specified machine instr
502 /// that is independent of the operand, and may be independent of the instr
503 /// itself.  This can be useful for portably encoding the comment character
504 /// or other bits of target-specific knowledge into the asmstrings.  The
505 /// syntax used is ${:comment}.  Targets can override this to add support
506 /// for their own strange codes.
PrintSpecial(const MachineInstr * MI,raw_ostream & OS,const char * Code) const507 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
508                               const char *Code) const {
509   if (!strcmp(Code, "private")) {
510     const DataLayout &DL = MF->getDataLayout();
511     OS << DL.getPrivateGlobalPrefix();
512   } else if (!strcmp(Code, "comment")) {
513     OS << MAI->getCommentString();
514   } else if (!strcmp(Code, "uid")) {
515     // Comparing the address of MI isn't sufficient, because machineinstrs may
516     // be allocated to the same address across functions.
517 
518     // If this is a new LastFn instruction, bump the counter.
519     if (LastMI != MI || LastFn != getFunctionNumber()) {
520       ++Counter;
521       LastMI = MI;
522       LastFn = getFunctionNumber();
523     }
524     OS << Counter;
525   } else {
526     std::string msg;
527     raw_string_ostream Msg(msg);
528     Msg << "Unknown special formatter '" << Code
529          << "' for machine instr: " << *MI;
530     report_fatal_error(Msg.str());
531   }
532 }
533 
534 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
535 /// instruction, using the specified assembler variant.  Targets should
536 /// override this to format as appropriate.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)537 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
538                                  unsigned AsmVariant, const char *ExtraCode,
539                                  raw_ostream &O) {
540   // Does this asm operand have a single letter operand modifier?
541   if (ExtraCode && ExtraCode[0]) {
542     if (ExtraCode[1] != 0) return true; // Unknown modifier.
543 
544     const MachineOperand &MO = MI->getOperand(OpNo);
545     switch (ExtraCode[0]) {
546     default:
547       return true;  // Unknown modifier.
548     case 'c': // Substitute immediate value without immediate syntax
549       if (MO.getType() != MachineOperand::MO_Immediate)
550         return true;
551       O << MO.getImm();
552       return false;
553     case 'n':  // Negate the immediate constant.
554       if (MO.getType() != MachineOperand::MO_Immediate)
555         return true;
556       O << -MO.getImm();
557       return false;
558     case 's':  // The GCC deprecated s modifier
559       if (MO.getType() != MachineOperand::MO_Immediate)
560         return true;
561       O << ((32 - MO.getImm()) & 31);
562       return false;
563     }
564   }
565   return true;
566 }
567 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)568 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
569                                        unsigned AsmVariant,
570                                        const char *ExtraCode, raw_ostream &O) {
571   // Target doesn't support this yet!
572   return true;
573 }
574 
emitInlineAsmStart() const575 void AsmPrinter::emitInlineAsmStart() const {}
576 
emitInlineAsmEnd(const MCSubtargetInfo & StartInfo,const MCSubtargetInfo * EndInfo) const577 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
578                                   const MCSubtargetInfo *EndInfo) const {}
579