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