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"
39using namespace llvm;
40
41#define DEBUG_TYPE "asm-printer"
42
43namespace {
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.
54static 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.
76void 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
156static 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
254static 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.
430void 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.
507void 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.
537bool 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
563bool 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
570void AsmPrinter::emitInlineAsmStart() const {}
571
572void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
573                                  const MCSubtargetInfo *EndInfo) const {}
574