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 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 
    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 
    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.
    430 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.
    507 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.
    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     }
    559   }
    560   return true;
    561 }
    562 
    563 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
    564                                        unsigned AsmVariant,
    565                                        const char *ExtraCode, raw_ostream &O) {
    566   // Target doesn't support this yet!
    567   return true;
    568 }
    569 
    570 void AsmPrinter::emitInlineAsmStart() const {}
    571 
    572 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
    573                                   const MCSubtargetInfo *EndInfo) const {}
    574