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