ParseStmtAsm.cpp revision 344779
1//===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===// 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 parsing for GCC and Microsoft inline assembly. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Parse/Parser.h" 15#include "clang/AST/ASTContext.h" 16#include "clang/Basic/Diagnostic.h" 17#include "clang/Basic/TargetInfo.h" 18#include "clang/Parse/RAIIObjectsForParser.h" 19#include "llvm/ADT/SmallString.h" 20#include "llvm/ADT/StringExtras.h" 21#include "llvm/MC/MCAsmInfo.h" 22#include "llvm/MC/MCContext.h" 23#include "llvm/MC/MCInstPrinter.h" 24#include "llvm/MC/MCInstrInfo.h" 25#include "llvm/MC/MCObjectFileInfo.h" 26#include "llvm/MC/MCParser/MCAsmParser.h" 27#include "llvm/MC/MCParser/MCTargetAsmParser.h" 28#include "llvm/MC/MCRegisterInfo.h" 29#include "llvm/MC/MCStreamer.h" 30#include "llvm/MC/MCSubtargetInfo.h" 31#include "llvm/MC/MCTargetOptions.h" 32#include "llvm/Support/SourceMgr.h" 33#include "llvm/Support/TargetRegistry.h" 34#include "llvm/Support/TargetSelect.h" 35using namespace clang; 36 37namespace { 38class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback { 39 Parser &TheParser; 40 SourceLocation AsmLoc; 41 StringRef AsmString; 42 43 /// The tokens we streamed into AsmString and handed off to MC. 44 ArrayRef<Token> AsmToks; 45 46 /// The offset of each token in AsmToks within AsmString. 47 ArrayRef<unsigned> AsmTokOffsets; 48 49public: 50 ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString, 51 ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets) 52 : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks), 53 AsmTokOffsets(Offsets) { 54 assert(AsmToks.size() == AsmTokOffsets.size()); 55 } 56 57 void LookupInlineAsmIdentifier(StringRef &LineBuf, 58 llvm::InlineAsmIdentifierInfo &Info, 59 bool IsUnevaluatedContext) override; 60 61 StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, 62 llvm::SMLoc Location, 63 bool Create) override; 64 65 bool LookupInlineAsmField(StringRef Base, StringRef Member, 66 unsigned &Offset) override { 67 return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset, 68 AsmLoc); 69 } 70 71 static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) { 72 ((ClangAsmParserCallback *)Context)->handleDiagnostic(D); 73 } 74 75private: 76 /// Collect the appropriate tokens for the given string. 77 void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks, 78 const Token *&FirstOrigToken) const; 79 80 SourceLocation translateLocation(const llvm::SourceMgr &LSM, 81 llvm::SMLoc SMLoc); 82 83 void handleDiagnostic(const llvm::SMDiagnostic &D); 84}; 85} 86 87void ClangAsmParserCallback::LookupInlineAsmIdentifier( 88 StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info, 89 bool IsUnevaluatedContext) { 90 // Collect the desired tokens. 91 SmallVector<Token, 16> LineToks; 92 const Token *FirstOrigToken = nullptr; 93 findTokensForString(LineBuf, LineToks, FirstOrigToken); 94 95 unsigned NumConsumedToks; 96 ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, 97 IsUnevaluatedContext); 98 99 // If we consumed the entire line, tell MC that. 100 // Also do this if we consumed nothing as a way of reporting failure. 101 if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { 102 // By not modifying LineBuf, we're implicitly consuming it all. 103 104 // Otherwise, consume up to the original tokens. 105 } else { 106 assert(FirstOrigToken && "not using original tokens?"); 107 108 // Since we're using original tokens, apply that offset. 109 assert(FirstOrigToken[NumConsumedToks].getLocation() == 110 LineToks[NumConsumedToks].getLocation()); 111 unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); 112 unsigned LastIndex = FirstIndex + NumConsumedToks - 1; 113 114 // The total length we've consumed is the relative offset 115 // of the last token we consumed plus its length. 116 unsigned TotalOffset = 117 (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() - 118 AsmTokOffsets[FirstIndex]); 119 LineBuf = LineBuf.substr(0, TotalOffset); 120 } 121 122 // Initialize Info with the lookup result. 123 if (!Result.isUsable()) 124 return; 125 TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info); 126} 127 128StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier, 129 llvm::SourceMgr &LSM, 130 llvm::SMLoc Location, 131 bool Create) { 132 SourceLocation Loc = translateLocation(LSM, Location); 133 LabelDecl *Label = 134 TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); 135 return Label->getMSAsmLabel(); 136} 137 138void ClangAsmParserCallback::findTokensForString( 139 StringRef Str, SmallVectorImpl<Token> &TempToks, 140 const Token *&FirstOrigToken) const { 141 // For now, assert that the string we're working with is a substring 142 // of what we gave to MC. This lets us use the original tokens. 143 assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) && 144 !std::less<const char *>()(AsmString.end(), Str.end())); 145 146 // Try to find a token whose offset matches the first token. 147 unsigned FirstCharOffset = Str.begin() - AsmString.begin(); 148 const unsigned *FirstTokOffset = std::lower_bound( 149 AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset); 150 151 // For now, assert that the start of the string exactly 152 // corresponds to the start of a token. 153 assert(*FirstTokOffset == FirstCharOffset); 154 155 // Use all the original tokens for this line. (We assume the 156 // end of the line corresponds cleanly to a token break.) 157 unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); 158 FirstOrigToken = &AsmToks[FirstTokIndex]; 159 unsigned LastCharOffset = Str.end() - AsmString.begin(); 160 for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { 161 if (AsmTokOffsets[i] >= LastCharOffset) 162 break; 163 TempToks.push_back(AsmToks[i]); 164 } 165} 166 167SourceLocation 168ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM, 169 llvm::SMLoc SMLoc) { 170 // Compute an offset into the inline asm buffer. 171 // FIXME: This isn't right if .macro is involved (but hopefully, no 172 // real-world code does that). 173 const llvm::MemoryBuffer *LBuf = 174 LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc)); 175 unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); 176 177 // Figure out which token that offset points into. 178 const unsigned *TokOffsetPtr = 179 std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); 180 unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); 181 unsigned TokOffset = *TokOffsetPtr; 182 183 // If we come up with an answer which seems sane, use it; otherwise, 184 // just point at the __asm keyword. 185 // FIXME: Assert the answer is sane once we handle .macro correctly. 186 SourceLocation Loc = AsmLoc; 187 if (TokIndex < AsmToks.size()) { 188 const Token &Tok = AsmToks[TokIndex]; 189 Loc = Tok.getLocation(); 190 Loc = Loc.getLocWithOffset(Offset - TokOffset); 191 } 192 return Loc; 193} 194 195void ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) { 196 const llvm::SourceMgr &LSM = *D.getSourceMgr(); 197 SourceLocation Loc = translateLocation(LSM, D.getLoc()); 198 TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); 199} 200 201/// Parse an identifier in an MS-style inline assembly block. 202ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, 203 unsigned &NumLineToksConsumed, 204 bool IsUnevaluatedContext) { 205 // Push a fake token on the end so that we don't overrun the token 206 // stream. We use ';' because it expression-parsing should never 207 // overrun it. 208 const tok::TokenKind EndOfStream = tok::semi; 209 Token EndOfStreamTok; 210 EndOfStreamTok.startToken(); 211 EndOfStreamTok.setKind(EndOfStream); 212 LineToks.push_back(EndOfStreamTok); 213 214 // Also copy the current token over. 215 LineToks.push_back(Tok); 216 217 PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true); 218 219 // Clear the current token and advance to the first token in LineToks. 220 ConsumeAnyToken(); 221 222 // Parse an optional scope-specifier if we're in C++. 223 CXXScopeSpec SS; 224 if (getLangOpts().CPlusPlus) { 225 ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); 226 } 227 228 // Require an identifier here. 229 SourceLocation TemplateKWLoc; 230 UnqualifiedId Id; 231 bool Invalid = true; 232 ExprResult Result; 233 if (Tok.is(tok::kw_this)) { 234 Result = ParseCXXThis(); 235 Invalid = false; 236 } else { 237 Invalid = ParseUnqualifiedId(SS, 238 /*EnteringContext=*/false, 239 /*AllowDestructorName=*/false, 240 /*AllowConstructorName=*/false, 241 /*AllowDeductionGuide=*/false, 242 /*ObjectType=*/nullptr, &TemplateKWLoc, Id); 243 // Perform the lookup. 244 Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, 245 IsUnevaluatedContext); 246 } 247 // While the next two tokens are 'period' 'identifier', repeatedly parse it as 248 // a field access. We have to avoid consuming assembler directives that look 249 // like '.' 'else'. 250 while (Result.isUsable() && Tok.is(tok::period)) { 251 Token IdTok = PP.LookAhead(0); 252 if (IdTok.isNot(tok::identifier)) 253 break; 254 ConsumeToken(); // Consume the period. 255 IdentifierInfo *Id = Tok.getIdentifierInfo(); 256 ConsumeToken(); // Consume the identifier. 257 Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(), 258 Tok.getLocation()); 259 } 260 261 // Figure out how many tokens we are into LineToks. 262 unsigned LineIndex = 0; 263 if (Tok.is(EndOfStream)) { 264 LineIndex = LineToks.size() - 2; 265 } else { 266 while (LineToks[LineIndex].getLocation() != Tok.getLocation()) { 267 LineIndex++; 268 assert(LineIndex < LineToks.size() - 2); // we added two extra tokens 269 } 270 } 271 272 // If we've run into the poison token we inserted before, or there 273 // was a parsing error, then claim the entire line. 274 if (Invalid || Tok.is(EndOfStream)) { 275 NumLineToksConsumed = LineToks.size() - 2; 276 } else { 277 // Otherwise, claim up to the start of the next token. 278 NumLineToksConsumed = LineIndex; 279 } 280 281 // Finally, restore the old parsing state by consuming all the tokens we 282 // staged before, implicitly killing off the token-lexer we pushed. 283 for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) { 284 ConsumeAnyToken(); 285 } 286 assert(Tok.is(EndOfStream)); 287 ConsumeToken(); 288 289 // Leave LineToks in its original state. 290 LineToks.pop_back(); 291 LineToks.pop_back(); 292 293 return Result; 294} 295 296/// Turn a sequence of our tokens back into a string that we can hand 297/// to the MC asm parser. 298static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, 299 ArrayRef<Token> AsmToks, 300 SmallVectorImpl<unsigned> &TokOffsets, 301 SmallString<512> &Asm) { 302 assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!"); 303 304 // Is this the start of a new assembly statement? 305 bool isNewStatement = true; 306 307 for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { 308 const Token &Tok = AsmToks[i]; 309 310 // Start each new statement with a newline and a tab. 311 if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { 312 Asm += "\n\t"; 313 isNewStatement = true; 314 } 315 316 // Preserve the existence of leading whitespace except at the 317 // start of a statement. 318 if (!isNewStatement && Tok.hasLeadingSpace()) 319 Asm += ' '; 320 321 // Remember the offset of this token. 322 TokOffsets.push_back(Asm.size()); 323 324 // Don't actually write '__asm' into the assembly stream. 325 if (Tok.is(tok::kw_asm)) { 326 // Complain about __asm at the end of the stream. 327 if (i + 1 == e) { 328 PP.Diag(AsmLoc, diag::err_asm_empty); 329 return true; 330 } 331 332 continue; 333 } 334 335 // Append the spelling of the token. 336 SmallString<32> SpellingBuffer; 337 bool SpellingInvalid = false; 338 Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); 339 assert(!SpellingInvalid && "spelling was invalid after correct parse?"); 340 341 // We are no longer at the start of a statement. 342 isNewStatement = false; 343 } 344 345 // Ensure that the buffer is null-terminated. 346 Asm.push_back('\0'); 347 Asm.pop_back(); 348 349 assert(TokOffsets.size() == AsmToks.size()); 350 return false; 351} 352 353/// isTypeQualifier - Return true if the current token could be the 354/// start of a type-qualifier-list. 355static bool isTypeQualifier(const Token &Tok) { 356 switch (Tok.getKind()) { 357 default: return false; 358 // type-qualifier 359 case tok::kw_const: 360 case tok::kw_volatile: 361 case tok::kw_restrict: 362 case tok::kw___private: 363 case tok::kw___local: 364 case tok::kw___global: 365 case tok::kw___constant: 366 case tok::kw___generic: 367 case tok::kw___read_only: 368 case tok::kw___read_write: 369 case tok::kw___write_only: 370 return true; 371 } 372} 373 374// Determine if this is a GCC-style asm statement. 375static bool isGCCAsmStatement(const Token &TokAfterAsm) { 376 return TokAfterAsm.is(tok::l_paren) || TokAfterAsm.is(tok::kw_goto) || 377 isTypeQualifier(TokAfterAsm); 378} 379 380/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, 381/// this routine is called to collect the tokens for an MS asm statement. 382/// 383/// [MS] ms-asm-statement: 384/// ms-asm-block 385/// ms-asm-block ms-asm-statement 386/// 387/// [MS] ms-asm-block: 388/// '__asm' ms-asm-line '\n' 389/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] 390/// 391/// [MS] ms-asm-instruction-block 392/// ms-asm-line 393/// ms-asm-line '\n' ms-asm-instruction-block 394/// 395StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { 396 SourceManager &SrcMgr = PP.getSourceManager(); 397 SourceLocation EndLoc = AsmLoc; 398 SmallVector<Token, 4> AsmToks; 399 400 bool SingleLineMode = true; 401 unsigned BraceNesting = 0; 402 unsigned short savedBraceCount = BraceCount; 403 bool InAsmComment = false; 404 FileID FID; 405 unsigned LineNo = 0; 406 unsigned NumTokensRead = 0; 407 SmallVector<SourceLocation, 4> LBraceLocs; 408 bool SkippedStartOfLine = false; 409 410 if (Tok.is(tok::l_brace)) { 411 // Braced inline asm: consume the opening brace. 412 SingleLineMode = false; 413 BraceNesting = 1; 414 EndLoc = ConsumeBrace(); 415 LBraceLocs.push_back(EndLoc); 416 ++NumTokensRead; 417 } else { 418 // Single-line inline asm; compute which line it is on. 419 std::pair<FileID, unsigned> ExpAsmLoc = 420 SrcMgr.getDecomposedExpansionLoc(EndLoc); 421 FID = ExpAsmLoc.first; 422 LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); 423 LBraceLocs.push_back(SourceLocation()); 424 } 425 426 SourceLocation TokLoc = Tok.getLocation(); 427 do { 428 // If we hit EOF, we're done, period. 429 if (isEofOrEom()) 430 break; 431 432 if (!InAsmComment && Tok.is(tok::l_brace)) { 433 // Consume the opening brace. 434 SkippedStartOfLine = Tok.isAtStartOfLine(); 435 AsmToks.push_back(Tok); 436 EndLoc = ConsumeBrace(); 437 BraceNesting++; 438 LBraceLocs.push_back(EndLoc); 439 TokLoc = Tok.getLocation(); 440 ++NumTokensRead; 441 continue; 442 } else if (!InAsmComment && Tok.is(tok::semi)) { 443 // A semicolon in an asm is the start of a comment. 444 InAsmComment = true; 445 if (!SingleLineMode) { 446 // Compute which line the comment is on. 447 std::pair<FileID, unsigned> ExpSemiLoc = 448 SrcMgr.getDecomposedExpansionLoc(TokLoc); 449 FID = ExpSemiLoc.first; 450 LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); 451 } 452 } else if (SingleLineMode || InAsmComment) { 453 // If end-of-line is significant, check whether this token is on a 454 // new line. 455 std::pair<FileID, unsigned> ExpLoc = 456 SrcMgr.getDecomposedExpansionLoc(TokLoc); 457 if (ExpLoc.first != FID || 458 SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { 459 // If this is a single-line __asm, we're done, except if the next 460 // line is MS-style asm too, in which case we finish a comment 461 // if needed and then keep processing the next line as a single 462 // line __asm. 463 bool isAsm = Tok.is(tok::kw_asm); 464 if (SingleLineMode && (!isAsm || isGCCAsmStatement(NextToken()))) 465 break; 466 // We're no longer in a comment. 467 InAsmComment = false; 468 if (isAsm) { 469 // If this is a new __asm {} block we want to process it separately 470 // from the single-line __asm statements 471 if (PP.LookAhead(0).is(tok::l_brace)) 472 break; 473 LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second); 474 SkippedStartOfLine = Tok.isAtStartOfLine(); 475 } else if (Tok.is(tok::semi)) { 476 // A multi-line asm-statement, where next line is a comment 477 InAsmComment = true; 478 FID = ExpLoc.first; 479 LineNo = SrcMgr.getLineNumber(FID, ExpLoc.second); 480 } 481 } else if (!InAsmComment && Tok.is(tok::r_brace)) { 482 // In MSVC mode, braces only participate in brace matching and 483 // separating the asm statements. This is an intentional 484 // departure from the Apple gcc behavior. 485 if (!BraceNesting) 486 break; 487 } 488 } 489 if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) && 490 BraceCount == (savedBraceCount + BraceNesting)) { 491 // Consume the closing brace. 492 SkippedStartOfLine = Tok.isAtStartOfLine(); 493 // Don't want to add the closing brace of the whole asm block 494 if (SingleLineMode || BraceNesting > 1) { 495 Tok.clearFlag(Token::LeadingSpace); 496 AsmToks.push_back(Tok); 497 } 498 EndLoc = ConsumeBrace(); 499 BraceNesting--; 500 // Finish if all of the opened braces in the inline asm section were 501 // consumed. 502 if (BraceNesting == 0 && !SingleLineMode) 503 break; 504 else { 505 LBraceLocs.pop_back(); 506 TokLoc = Tok.getLocation(); 507 ++NumTokensRead; 508 continue; 509 } 510 } 511 512 // Consume the next token; make sure we don't modify the brace count etc. 513 // if we are in a comment. 514 EndLoc = TokLoc; 515 if (InAsmComment) 516 PP.Lex(Tok); 517 else { 518 // Set the token as the start of line if we skipped the original start 519 // of line token in case it was a nested brace. 520 if (SkippedStartOfLine) 521 Tok.setFlag(Token::StartOfLine); 522 AsmToks.push_back(Tok); 523 ConsumeAnyToken(); 524 } 525 TokLoc = Tok.getLocation(); 526 ++NumTokensRead; 527 SkippedStartOfLine = false; 528 } while (1); 529 530 if (BraceNesting && BraceCount != savedBraceCount) { 531 // __asm without closing brace (this can happen at EOF). 532 for (unsigned i = 0; i < BraceNesting; ++i) { 533 Diag(Tok, diag::err_expected) << tok::r_brace; 534 Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace; 535 LBraceLocs.pop_back(); 536 } 537 return StmtError(); 538 } else if (NumTokensRead == 0) { 539 // Empty __asm. 540 Diag(Tok, diag::err_expected) << tok::l_brace; 541 return StmtError(); 542 } 543 544 // Okay, prepare to use MC to parse the assembly. 545 SmallVector<StringRef, 4> ConstraintRefs; 546 SmallVector<Expr *, 4> Exprs; 547 SmallVector<StringRef, 4> ClobberRefs; 548 549 // We need an actual supported target. 550 const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple(); 551 llvm::Triple::ArchType ArchTy = TheTriple.getArch(); 552 const std::string &TT = TheTriple.getTriple(); 553 const llvm::Target *TheTarget = nullptr; 554 bool UnsupportedArch = 555 (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); 556 if (UnsupportedArch) { 557 Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); 558 } else { 559 std::string Error; 560 TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); 561 if (!TheTarget) 562 Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error; 563 } 564 565 assert(!LBraceLocs.empty() && "Should have at least one location here"); 566 567 // If we don't support assembly, or the assembly is empty, we don't 568 // need to instantiate the AsmParser, etc. 569 if (!TheTarget || AsmToks.empty()) { 570 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), 571 /*NumOutputs*/ 0, /*NumInputs*/ 0, 572 ConstraintRefs, ClobberRefs, Exprs, EndLoc); 573 } 574 575 // Expand the tokens into a string buffer. 576 SmallString<512> AsmString; 577 SmallVector<unsigned, 8> TokOffsets; 578 if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) 579 return StmtError(); 580 581 const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts(); 582 std::string FeaturesStr = 583 llvm::join(TO.Features.begin(), TO.Features.end(), ","); 584 585 std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); 586 std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); 587 // Get the instruction descriptor. 588 std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 589 std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); 590 std::unique_ptr<llvm::MCSubtargetInfo> STI( 591 TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); 592 593 llvm::SourceMgr TempSrcMgr; 594 llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); 595 MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx); 596 std::unique_ptr<llvm::MemoryBuffer> Buffer = 597 llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); 598 599 // Tell SrcMgr about this buffer, which is what the parser will pick up. 600 TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc()); 601 602 std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); 603 std::unique_ptr<llvm::MCAsmParser> Parser( 604 createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); 605 606 // FIXME: init MCOptions from sanitizer flags here. 607 llvm::MCTargetOptions MCOptions; 608 std::unique_ptr<llvm::MCTargetAsmParser> TargetParser( 609 TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); 610 611 std::unique_ptr<llvm::MCInstPrinter> IP( 612 TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); 613 614 // Change to the Intel dialect. 615 Parser->setAssemblerDialect(1); 616 Parser->setTargetParser(*TargetParser.get()); 617 Parser->setParsingInlineAsm(true); 618 TargetParser->setParsingInlineAsm(true); 619 620 ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks, 621 TokOffsets); 622 TargetParser->setSemaCallback(&Callback); 623 TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback, 624 &Callback); 625 626 unsigned NumOutputs; 627 unsigned NumInputs; 628 std::string AsmStringIR; 629 SmallVector<std::pair<void *, bool>, 4> OpExprs; 630 SmallVector<std::string, 4> Constraints; 631 SmallVector<std::string, 4> Clobbers; 632 if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs, 633 NumInputs, OpExprs, Constraints, Clobbers, 634 MII.get(), IP.get(), Callback)) 635 return StmtError(); 636 637 // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber 638 // constraints. Clang always adds fpsr to the clobber list anyway. 639 llvm::erase_if(Clobbers, [](const std::string &C) { 640 return C == "fpsr" || C == "mxcsr"; 641 }); 642 643 // Build the vector of clobber StringRefs. 644 ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end()); 645 646 // Recast the void pointers and build the vector of constraint StringRefs. 647 unsigned NumExprs = NumOutputs + NumInputs; 648 ConstraintRefs.resize(NumExprs); 649 Exprs.resize(NumExprs); 650 for (unsigned i = 0, e = NumExprs; i != e; ++i) { 651 Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first); 652 if (!OpExpr) 653 return StmtError(); 654 655 // Need address of variable. 656 if (OpExprs[i].second) 657 OpExpr = 658 Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get(); 659 660 ConstraintRefs[i] = StringRef(Constraints[i]); 661 Exprs[i] = OpExpr; 662 } 663 664 // FIXME: We should be passing source locations for better diagnostics. 665 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR, 666 NumOutputs, NumInputs, ConstraintRefs, 667 ClobberRefs, Exprs, EndLoc); 668} 669 670/// ParseAsmStatement - Parse a GNU extended asm statement. 671/// asm-statement: 672/// gnu-asm-statement 673/// ms-asm-statement 674/// 675/// [GNU] gnu-asm-statement: 676/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' 677/// 678/// [GNU] asm-argument: 679/// asm-string-literal 680/// asm-string-literal ':' asm-operands[opt] 681/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 682/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 683/// ':' asm-clobbers 684/// 685/// [GNU] asm-clobbers: 686/// asm-string-literal 687/// asm-clobbers ',' asm-string-literal 688/// 689StmtResult Parser::ParseAsmStatement(bool &msAsm) { 690 assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); 691 SourceLocation AsmLoc = ConsumeToken(); 692 693 if (getLangOpts().AsmBlocks && !isGCCAsmStatement(Tok)) { 694 msAsm = true; 695 return ParseMicrosoftAsmStatement(AsmLoc); 696 } 697 698 DeclSpec DS(AttrFactory); 699 SourceLocation Loc = Tok.getLocation(); 700 ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); 701 702 // GNU asms accept, but warn, about type-qualifiers other than volatile. 703 if (DS.getTypeQualifiers() & DeclSpec::TQ_const) 704 Diag(Loc, diag::warn_asm_qualifier_ignored) << "const"; 705 if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) 706 Diag(Loc, diag::warn_asm_qualifier_ignored) << "restrict"; 707 // FIXME: Once GCC supports _Atomic, check whether it permits it here. 708 if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) 709 Diag(Loc, diag::warn_asm_qualifier_ignored) << "_Atomic"; 710 711 // Remember if this was a volatile asm. 712 bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; 713 714 // TODO: support "asm goto" constructs (PR#9295). 715 if (Tok.is(tok::kw_goto)) { 716 Diag(Tok, diag::err_asm_goto_not_supported_yet); 717 SkipUntil(tok::r_paren, StopAtSemi); 718 return StmtError(); 719 } 720 721 if (Tok.isNot(tok::l_paren)) { 722 Diag(Tok, diag::err_expected_lparen_after) << "asm"; 723 SkipUntil(tok::r_paren, StopAtSemi); 724 return StmtError(); 725 } 726 BalancedDelimiterTracker T(*this, tok::l_paren); 727 T.consumeOpen(); 728 729 ExprResult AsmString(ParseAsmStringLiteral()); 730 731 // Check if GNU-style InlineAsm is disabled. 732 // Error on anything other than empty string. 733 if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) { 734 const auto *SL = cast<StringLiteral>(AsmString.get()); 735 if (!SL->getString().trim().empty()) 736 Diag(Loc, diag::err_gnu_inline_asm_disabled); 737 } 738 739 if (AsmString.isInvalid()) { 740 // Consume up to and including the closing paren. 741 T.skipToEnd(); 742 return StmtError(); 743 } 744 745 SmallVector<IdentifierInfo *, 4> Names; 746 ExprVector Constraints; 747 ExprVector Exprs; 748 ExprVector Clobbers; 749 750 if (Tok.is(tok::r_paren)) { 751 // We have a simple asm expression like 'asm("foo")'. 752 T.consumeClose(); 753 return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, 754 /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, 755 Constraints, Exprs, AsmString.get(), 756 Clobbers, T.getCloseLocation()); 757 } 758 759 // Parse Outputs, if present. 760 bool AteExtraColon = false; 761 if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 762 // In C++ mode, parse "::" like ": :". 763 AteExtraColon = Tok.is(tok::coloncolon); 764 ConsumeToken(); 765 766 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 767 return StmtError(); 768 } 769 770 unsigned NumOutputs = Names.size(); 771 772 // Parse Inputs, if present. 773 if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 774 // In C++ mode, parse "::" like ": :". 775 if (AteExtraColon) 776 AteExtraColon = false; 777 else { 778 AteExtraColon = Tok.is(tok::coloncolon); 779 ConsumeToken(); 780 } 781 782 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 783 return StmtError(); 784 } 785 786 assert(Names.size() == Constraints.size() && 787 Constraints.size() == Exprs.size() && "Input operand size mismatch!"); 788 789 unsigned NumInputs = Names.size() - NumOutputs; 790 791 // Parse the clobbers, if present. 792 if (AteExtraColon || Tok.is(tok::colon)) { 793 if (!AteExtraColon) 794 ConsumeToken(); 795 796 // Parse the asm-string list for clobbers if present. 797 if (Tok.isNot(tok::r_paren)) { 798 while (1) { 799 ExprResult Clobber(ParseAsmStringLiteral()); 800 801 if (Clobber.isInvalid()) 802 break; 803 804 Clobbers.push_back(Clobber.get()); 805 806 if (!TryConsumeToken(tok::comma)) 807 break; 808 } 809 } 810 } 811 812 T.consumeClose(); 813 return Actions.ActOnGCCAsmStmt( 814 AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), 815 Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); 816} 817 818/// ParseAsmOperands - Parse the asm-operands production as used by 819/// asm-statement, assuming the leading ':' token was eaten. 820/// 821/// [GNU] asm-operands: 822/// asm-operand 823/// asm-operands ',' asm-operand 824/// 825/// [GNU] asm-operand: 826/// asm-string-literal '(' expression ')' 827/// '[' identifier ']' asm-string-literal '(' expression ')' 828/// 829// 830// FIXME: Avoid unnecessary std::string trashing. 831bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, 832 SmallVectorImpl<Expr *> &Constraints, 833 SmallVectorImpl<Expr *> &Exprs) { 834 // 'asm-operands' isn't present? 835 if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) 836 return false; 837 838 while (1) { 839 // Read the [id] if present. 840 if (Tok.is(tok::l_square)) { 841 BalancedDelimiterTracker T(*this, tok::l_square); 842 T.consumeOpen(); 843 844 if (Tok.isNot(tok::identifier)) { 845 Diag(Tok, diag::err_expected) << tok::identifier; 846 SkipUntil(tok::r_paren, StopAtSemi); 847 return true; 848 } 849 850 IdentifierInfo *II = Tok.getIdentifierInfo(); 851 ConsumeToken(); 852 853 Names.push_back(II); 854 T.consumeClose(); 855 } else 856 Names.push_back(nullptr); 857 858 ExprResult Constraint(ParseAsmStringLiteral()); 859 if (Constraint.isInvalid()) { 860 SkipUntil(tok::r_paren, StopAtSemi); 861 return true; 862 } 863 Constraints.push_back(Constraint.get()); 864 865 if (Tok.isNot(tok::l_paren)) { 866 Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; 867 SkipUntil(tok::r_paren, StopAtSemi); 868 return true; 869 } 870 871 // Read the parenthesized expression. 872 BalancedDelimiterTracker T(*this, tok::l_paren); 873 T.consumeOpen(); 874 ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression()); 875 T.consumeClose(); 876 if (Res.isInvalid()) { 877 SkipUntil(tok::r_paren, StopAtSemi); 878 return true; 879 } 880 Exprs.push_back(Res.get()); 881 // Eat the comma and continue parsing if it exists. 882 if (!TryConsumeToken(tok::comma)) 883 return false; 884 } 885} 886