AsmPrinterInlineAsm.cpp 25 KB

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