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