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