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