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