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 (isDigit(*IDEnd)) 238 ++IDEnd; 239 240 unsigned Val; 241 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) 242 report_fatal_error("Bad $ operand number in inline asm string: '" + 243 Twine(AsmStr) + "'"); 244 LastEmitted = IDEnd; 245 246 if (Val >= NumOperands-1) 247 report_fatal_error("Invalid $ operand number in inline asm string: '" + 248 Twine(AsmStr) + "'"); 249 250 char Modifier[2] = { 0, 0 }; 251 252 if (HasCurlyBraces) { 253 // If we have curly braces, check for a modifier character. This 254 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. 255 if (*LastEmitted == ':') { 256 ++LastEmitted; // Consume ':' character. 257 if (*LastEmitted == 0) 258 report_fatal_error("Bad ${:} expression in inline asm string: '" + 259 Twine(AsmStr) + "'"); 260 261 Modifier[0] = *LastEmitted; 262 ++LastEmitted; // Consume modifier character. 263 } 264 265 if (*LastEmitted != '}') 266 report_fatal_error("Bad ${} expression in inline asm string: '" + 267 Twine(AsmStr) + "'"); 268 ++LastEmitted; // Consume '}' character. 269 } 270 271 // Okay, we finally have a value number. Ask the target to print this 272 // operand! 273 unsigned OpNo = InlineAsm::MIOp_FirstOperand; 274 275 bool Error = false; 276 277 // Scan to find the machine operand number for the operand. 278 for (; Val; --Val) { 279 if (OpNo >= MI->getNumOperands()) break; 280 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 281 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; 282 } 283 284 // We may have a location metadata attached to the end of the 285 // instruction, and at no point should see metadata at any 286 // other point while processing. It's an error if so. 287 if (OpNo >= MI->getNumOperands() || 288 MI->getOperand(OpNo).isMetadata()) { 289 Error = true; 290 } else { 291 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 292 ++OpNo; // Skip over the ID number. 293 294 if (InlineAsm::isMemKind(OpFlags)) { 295 Error = AP->PrintAsmMemoryOperand( 296 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); 297 } else { 298 Error = AP->PrintAsmOperand(MI, OpNo, 299 Modifier[0] ? Modifier : nullptr, OS); 300 } 301 } 302 if (Error) { 303 std::string msg; 304 raw_string_ostream Msg(msg); 305 Msg << "invalid operand in inline asm: '" << AsmStr << "'"; 306 MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); 307 } 308 break; 309 } 310 } 311 } 312 OS << "\n\t.att_syntax\n" << (char)0; // null terminate string. 313 } 314 315 static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, 316 MachineModuleInfo *MMI, int AsmPrinterVariant, 317 AsmPrinter *AP, unsigned LocCookie, 318 raw_ostream &OS) { 319 int CurVariant = -1; // The number of the {.|.|.} region we are in. 320 const char *LastEmitted = AsmStr; // One past the last character emitted. 321 unsigned NumOperands = MI->getNumOperands(); 322 323 OS << '\t'; 324 325 while (*LastEmitted) { 326 switch (*LastEmitted) { 327 default: { 328 // Not a special case, emit the string section literally. 329 const char *LiteralEnd = LastEmitted+1; 330 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && 331 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') 332 ++LiteralEnd; 333 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 334 OS.write(LastEmitted, LiteralEnd-LastEmitted); 335 LastEmitted = LiteralEnd; 336 break; 337 } 338 case '\n': 339 ++LastEmitted; // Consume newline character. 340 OS << '\n'; // Indent code with newline. 341 break; 342 case '$': { 343 ++LastEmitted; // Consume '$' character. 344 bool Done = true; 345 346 // Handle escapes. 347 switch (*LastEmitted) { 348 default: Done = false; break; 349 case '$': // $$ -> $ 350 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 351 OS << '$'; 352 ++LastEmitted; // Consume second '$' character. 353 break; 354 case '(': // $( -> same as GCC's { character. 355 ++LastEmitted; // Consume '(' character. 356 if (CurVariant != -1) 357 report_fatal_error("Nested variants found in inline asm string: '" + 358 Twine(AsmStr) + "'"); 359 CurVariant = 0; // We're in the first variant now. 360 break; 361 case '|': 362 ++LastEmitted; // consume '|' character. 363 if (CurVariant == -1) 364 OS << '|'; // this is gcc's behavior for | outside a variant 365 else 366 ++CurVariant; // We're in the next variant. 367 break; 368 case ')': // $) -> same as GCC's } char. 369 ++LastEmitted; // consume ')' character. 370 if (CurVariant == -1) 371 OS << '}'; // this is gcc's behavior for } outside a variant 372 else 373 CurVariant = -1; 374 break; 375 } 376 if (Done) break; 377 378 bool HasCurlyBraces = false; 379 if (*LastEmitted == '{') { // ${variable} 380 ++LastEmitted; // Consume '{' character. 381 HasCurlyBraces = true; 382 } 383 384 // If we have ${:foo}, then this is not a real operand reference, it is a 385 // "magic" string reference, just like in .td files. Arrange to call 386 // PrintSpecial. 387 if (HasCurlyBraces && *LastEmitted == ':') { 388 ++LastEmitted; 389 const char *StrStart = LastEmitted; 390 const char *StrEnd = strchr(StrStart, '}'); 391 if (!StrEnd) 392 report_fatal_error("Unterminated ${:foo} operand in inline asm" 393 " string: '" + Twine(AsmStr) + "'"); 394 395 std::string Val(StrStart, StrEnd); 396 AP->PrintSpecial(MI, OS, Val.c_str()); 397 LastEmitted = StrEnd+1; 398 break; 399 } 400 401 const char *IDStart = LastEmitted; 402 const char *IDEnd = IDStart; 403 while (isDigit(*IDEnd)) 404 ++IDEnd; 405 406 unsigned Val; 407 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) 408 report_fatal_error("Bad $ operand number in inline asm string: '" + 409 Twine(AsmStr) + "'"); 410 LastEmitted = IDEnd; 411 412 char Modifier[2] = { 0, 0 }; 413 414 if (HasCurlyBraces) { 415 // If we have curly braces, check for a modifier character. This 416 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. 417 if (*LastEmitted == ':') { 418 ++LastEmitted; // Consume ':' character. 419 if (*LastEmitted == 0) 420 report_fatal_error("Bad ${:} expression in inline asm string: '" + 421 Twine(AsmStr) + "'"); 422 423 Modifier[0] = *LastEmitted; 424 ++LastEmitted; // Consume modifier character. 425 } 426 427 if (*LastEmitted != '}') 428 report_fatal_error("Bad ${} expression in inline asm string: '" + 429 Twine(AsmStr) + "'"); 430 ++LastEmitted; // Consume '}' character. 431 } 432 433 if (Val >= NumOperands-1) 434 report_fatal_error("Invalid $ operand number in inline asm string: '" + 435 Twine(AsmStr) + "'"); 436 437 // Okay, we finally have a value number. Ask the target to print this 438 // operand! 439 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { 440 unsigned OpNo = InlineAsm::MIOp_FirstOperand; 441 442 bool Error = false; 443 444 // Scan to find the machine operand number for the operand. 445 for (; Val; --Val) { 446 if (OpNo >= MI->getNumOperands()) break; 447 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 448 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; 449 } 450 451 // We may have a location metadata attached to the end of the 452 // instruction, and at no point should see metadata at any 453 // other point while processing. It's an error if so. 454 if (OpNo >= MI->getNumOperands() || 455 MI->getOperand(OpNo).isMetadata()) { 456 Error = true; 457 } else { 458 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 459 ++OpNo; // Skip over the ID number. 460 461 // FIXME: Shouldn't arch-independent output template handling go into 462 // PrintAsmOperand? 463 // Labels are target independent. 464 if (MI->getOperand(OpNo).isBlockAddress()) { 465 const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress(); 466 MCSymbol *Sym = AP->GetBlockAddressSymbol(BA); 467 Sym->print(OS, AP->MAI); 468 MMI->getContext().registerInlineAsmLabel(Sym); 469 } else if (MI->getOperand(OpNo).isMBB()) { 470 const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); 471 Sym->print(OS, AP->MAI); 472 } else if (Modifier[0] == 'l') { 473 Error = true; 474 } else if (InlineAsm::isMemKind(OpFlags)) { 475 Error = AP->PrintAsmMemoryOperand( 476 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); 477 } else { 478 Error = AP->PrintAsmOperand(MI, OpNo, 479 Modifier[0] ? Modifier : nullptr, OS); 480 } 481 } 482 if (Error) { 483 std::string msg; 484 raw_string_ostream Msg(msg); 485 Msg << "invalid operand in inline asm: '" << AsmStr << "'"; 486 MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); 487 } 488 } 489 break; 490 } 491 } 492 } 493 OS << '\n' << (char)0; // null terminate string. 494 } 495 496 /// This method formats and emits the specified machine instruction that is an 497 /// inline asm. 498 void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { 499 assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); 500 501 // Count the number of register definitions to find the asm string. 502 unsigned NumDefs = 0; 503 for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); 504 ++NumDefs) 505 assert(NumDefs != MI->getNumOperands()-2 && "No asm string?"); 506 507 assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); 508 509 // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. 510 const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); 511 512 // If this asmstr is empty, just print the #APP/#NOAPP markers. 513 // These are useful to see where empty asm's wound up. 514 if (AsmStr[0] == 0) { 515 OutStreamer->emitRawComment(MAI->getInlineAsmStart()); 516 OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); 517 return; 518 } 519 520 // Emit the #APP start marker. This has to happen even if verbose-asm isn't 521 // enabled, so we use emitRawComment. 522 OutStreamer->emitRawComment(MAI->getInlineAsmStart()); 523 524 // Get the !srcloc metadata node if we have it, and decode the loc cookie from 525 // it. 526 unsigned LocCookie = 0; 527 const MDNode *LocMD = nullptr; 528 for (unsigned i = MI->getNumOperands(); i != 0; --i) { 529 if (MI->getOperand(i-1).isMetadata() && 530 (LocMD = MI->getOperand(i-1).getMetadata()) && 531 LocMD->getNumOperands() != 0) { 532 if (const ConstantInt *CI = 533 mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) { 534 LocCookie = CI->getZExtValue(); 535 break; 536 } 537 } 538 } 539 540 // Emit the inline asm to a temporary string so we can emit it through 541 // EmitInlineAsm. 542 SmallString<256> StringData; 543 raw_svector_ostream OS(StringData); 544 545 // The variant of the current asmprinter. 546 int AsmPrinterVariant = MAI->getAssemblerDialect(); 547 AsmPrinter *AP = const_cast<AsmPrinter*>(this); 548 if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) 549 EmitGCCInlineAsmStr(AsmStr, MI, MMI, AsmPrinterVariant, AP, LocCookie, OS); 550 else 551 EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); 552 553 // Emit warnings if we use reserved registers on the clobber list, as 554 // that might lead to undefined behaviour. 555 SmallVector<Register, 8> RestrRegs; 556 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 557 // Start with the first operand descriptor, and iterate over them. 558 for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands(); 559 I < NumOps; ++I) { 560 const MachineOperand &MO = MI->getOperand(I); 561 if (!MO.isImm()) 562 continue; 563 unsigned Flags = MO.getImm(); 564 if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) { 565 Register Reg = MI->getOperand(I + 1).getReg(); 566 if (!TRI->isAsmClobberable(*MF, Reg)) 567 RestrRegs.push_back(Reg); 568 } 569 // Skip to one before the next operand descriptor, if it exists. 570 I += InlineAsm::getNumOperandRegisters(Flags); 571 } 572 573 if (!RestrRegs.empty()) { 574 unsigned BufNum = addInlineAsmDiagBuffer(OS.str(), LocMD); 575 auto &SrcMgr = DiagInfo->SrcMgr; 576 SMLoc Loc = SMLoc::getFromPointer( 577 SrcMgr.getMemoryBuffer(BufNum)->getBuffer().begin()); 578 579 std::string Msg = "inline asm clobber list contains reserved registers: "; 580 for (auto I = RestrRegs.begin(), E = RestrRegs.end(); I != E; ++I) { 581 if(I != RestrRegs.begin()) 582 Msg += ", "; 583 Msg += TRI->getName(*I); 584 } 585 const char *Note = 586 "Reserved registers on the clobber list may not be " 587 "preserved across the asm statement, and clobbering them may " 588 "lead to undefined behaviour."; 589 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Warning, Msg); 590 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, Note); 591 } 592 593 emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD, 594 MI->getInlineAsmDialect()); 595 596 // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't 597 // enabled, so we use emitRawComment. 598 OutStreamer->emitRawComment(MAI->getInlineAsmEnd()); 599 } 600 601 /// PrintSpecial - Print information related to the specified machine instr 602 /// that is independent of the operand, and may be independent of the instr 603 /// itself. This can be useful for portably encoding the comment character 604 /// or other bits of target-specific knowledge into the asmstrings. The 605 /// syntax used is ${:comment}. Targets can override this to add support 606 /// for their own strange codes. 607 void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, 608 const char *Code) const { 609 if (!strcmp(Code, "private")) { 610 const DataLayout &DL = MF->getDataLayout(); 611 OS << DL.getPrivateGlobalPrefix(); 612 } else if (!strcmp(Code, "comment")) { 613 OS << MAI->getCommentString(); 614 } else if (!strcmp(Code, "uid")) { 615 // Comparing the address of MI isn't sufficient, because machineinstrs may 616 // be allocated to the same address across functions. 617 618 // If this is a new LastFn instruction, bump the counter. 619 if (LastMI != MI || LastFn != getFunctionNumber()) { 620 ++Counter; 621 LastMI = MI; 622 LastFn = getFunctionNumber(); 623 } 624 OS << Counter; 625 } else { 626 std::string msg; 627 raw_string_ostream Msg(msg); 628 Msg << "Unknown special formatter '" << Code 629 << "' for machine instr: " << *MI; 630 report_fatal_error(Msg.str()); 631 } 632 } 633 634 void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) { 635 assert(MO.isGlobal() && "caller should check MO.isGlobal"); 636 getSymbol(MO.getGlobal())->print(OS, MAI); 637 printOffset(MO.getOffset(), OS); 638 } 639 640 /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM 641 /// instruction, using the specified assembler variant. Targets should 642 /// override this to format as appropriate for machine specific ExtraCodes 643 /// or when the arch-independent handling would be too complex otherwise. 644 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 645 const char *ExtraCode, raw_ostream &O) { 646 // Does this asm operand have a single letter operand modifier? 647 if (ExtraCode && ExtraCode[0]) { 648 if (ExtraCode[1] != 0) return true; // Unknown modifier. 649 650 // https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html 651 const MachineOperand &MO = MI->getOperand(OpNo); 652 switch (ExtraCode[0]) { 653 default: 654 return true; // Unknown modifier. 655 case 'a': // Print as memory address. 656 if (MO.isReg()) { 657 PrintAsmMemoryOperand(MI, OpNo, nullptr, O); 658 return false; 659 } 660 LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates. 661 case 'c': // Substitute immediate value without immediate syntax 662 if (MO.isImm()) { 663 O << MO.getImm(); 664 return false; 665 } 666 if (MO.isGlobal()) { 667 PrintSymbolOperand(MO, O); 668 return false; 669 } 670 return true; 671 case 'n': // Negate the immediate constant. 672 if (!MO.isImm()) 673 return true; 674 O << -MO.getImm(); 675 return false; 676 case 's': // The GCC deprecated s modifier 677 if (!MO.isImm()) 678 return true; 679 O << ((32 - MO.getImm()) & 31); 680 return false; 681 } 682 } 683 return true; 684 } 685 686 bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 687 const char *ExtraCode, raw_ostream &O) { 688 // Target doesn't support this yet! 689 return true; 690 } 691 692 void AsmPrinter::emitInlineAsmStart() const {} 693 694 void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, 695 const MCSubtargetInfo *EndInfo) const {} 696