ParseStmtAsm.cpp revision 296417
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" 34using namespace clang; 35 36namespace { 37class 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 48public: 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 115private: 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. 183ExprResult 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 Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(), 245 Info, Tok.getLocation()); 246 } 247 248 // Figure out how many tokens we are into LineToks. 249 unsigned LineIndex = 0; 250 if (Tok.is(EndOfStream)) { 251 LineIndex = LineToks.size() - 2; 252 } else { 253 while (LineToks[LineIndex].getLocation() != Tok.getLocation()) { 254 LineIndex++; 255 assert(LineIndex < LineToks.size() - 2); // we added two extra tokens 256 } 257 } 258 259 // If we've run into the poison token we inserted before, or there 260 // was a parsing error, then claim the entire line. 261 if (Invalid || Tok.is(EndOfStream)) { 262 NumLineToksConsumed = LineToks.size() - 2; 263 } else { 264 // Otherwise, claim up to the start of the next token. 265 NumLineToksConsumed = LineIndex; 266 } 267 268 // Finally, restore the old parsing state by consuming all the tokens we 269 // staged before, implicitly killing off the token-lexer we pushed. 270 for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) { 271 ConsumeAnyToken(); 272 } 273 assert(Tok.is(EndOfStream)); 274 ConsumeToken(); 275 276 // Leave LineToks in its original state. 277 LineToks.pop_back(); 278 LineToks.pop_back(); 279 280 return Result; 281} 282 283/// Turn a sequence of our tokens back into a string that we can hand 284/// to the MC asm parser. 285static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, 286 ArrayRef<Token> AsmToks, 287 SmallVectorImpl<unsigned> &TokOffsets, 288 SmallString<512> &Asm) { 289 assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!"); 290 291 // Is this the start of a new assembly statement? 292 bool isNewStatement = true; 293 294 for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { 295 const Token &Tok = AsmToks[i]; 296 297 // Start each new statement with a newline and a tab. 298 if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { 299 Asm += "\n\t"; 300 isNewStatement = true; 301 } 302 303 // Preserve the existence of leading whitespace except at the 304 // start of a statement. 305 if (!isNewStatement && Tok.hasLeadingSpace()) 306 Asm += ' '; 307 308 // Remember the offset of this token. 309 TokOffsets.push_back(Asm.size()); 310 311 // Don't actually write '__asm' into the assembly stream. 312 if (Tok.is(tok::kw_asm)) { 313 // Complain about __asm at the end of the stream. 314 if (i + 1 == e) { 315 PP.Diag(AsmLoc, diag::err_asm_empty); 316 return true; 317 } 318 319 continue; 320 } 321 322 // Append the spelling of the token. 323 SmallString<32> SpellingBuffer; 324 bool SpellingInvalid = false; 325 Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); 326 assert(!SpellingInvalid && "spelling was invalid after correct parse?"); 327 328 // We are no longer at the start of a statement. 329 isNewStatement = false; 330 } 331 332 // Ensure that the buffer is null-terminated. 333 Asm.push_back('\0'); 334 Asm.pop_back(); 335 336 assert(TokOffsets.size() == AsmToks.size()); 337 return false; 338} 339 340/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, 341/// this routine is called to collect the tokens for an MS asm statement. 342/// 343/// [MS] ms-asm-statement: 344/// ms-asm-block 345/// ms-asm-block ms-asm-statement 346/// 347/// [MS] ms-asm-block: 348/// '__asm' ms-asm-line '\n' 349/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] 350/// 351/// [MS] ms-asm-instruction-block 352/// ms-asm-line 353/// ms-asm-line '\n' ms-asm-instruction-block 354/// 355StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { 356 SourceManager &SrcMgr = PP.getSourceManager(); 357 SourceLocation EndLoc = AsmLoc; 358 SmallVector<Token, 4> AsmToks; 359 360 bool SingleLineMode = true; 361 unsigned BraceNesting = 0; 362 unsigned short savedBraceCount = BraceCount; 363 bool InAsmComment = false; 364 FileID FID; 365 unsigned LineNo = 0; 366 unsigned NumTokensRead = 0; 367 SmallVector<SourceLocation, 4> LBraceLocs; 368 bool SkippedStartOfLine = false; 369 370 if (Tok.is(tok::l_brace)) { 371 // Braced inline asm: consume the opening brace. 372 SingleLineMode = false; 373 BraceNesting = 1; 374 EndLoc = ConsumeBrace(); 375 LBraceLocs.push_back(EndLoc); 376 ++NumTokensRead; 377 } else { 378 // Single-line inline asm; compute which line it is on. 379 std::pair<FileID, unsigned> ExpAsmLoc = 380 SrcMgr.getDecomposedExpansionLoc(EndLoc); 381 FID = ExpAsmLoc.first; 382 LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); 383 LBraceLocs.push_back(SourceLocation()); 384 } 385 386 SourceLocation TokLoc = Tok.getLocation(); 387 do { 388 // If we hit EOF, we're done, period. 389 if (isEofOrEom()) 390 break; 391 392 if (!InAsmComment && Tok.is(tok::l_brace)) { 393 // Consume the opening brace. 394 SkippedStartOfLine = Tok.isAtStartOfLine(); 395 EndLoc = ConsumeBrace(); 396 BraceNesting++; 397 LBraceLocs.push_back(EndLoc); 398 TokLoc = Tok.getLocation(); 399 ++NumTokensRead; 400 continue; 401 } else if (!InAsmComment && Tok.is(tok::semi)) { 402 // A semicolon in an asm is the start of a comment. 403 InAsmComment = true; 404 if (!SingleLineMode) { 405 // Compute which line the comment is on. 406 std::pair<FileID, unsigned> ExpSemiLoc = 407 SrcMgr.getDecomposedExpansionLoc(TokLoc); 408 FID = ExpSemiLoc.first; 409 LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); 410 } 411 } else if (SingleLineMode || InAsmComment) { 412 // If end-of-line is significant, check whether this token is on a 413 // new line. 414 std::pair<FileID, unsigned> ExpLoc = 415 SrcMgr.getDecomposedExpansionLoc(TokLoc); 416 if (ExpLoc.first != FID || 417 SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { 418 // If this is a single-line __asm, we're done, except if the next 419 // line begins with an __asm too, in which case we finish a comment 420 // if needed and then keep processing the next line as a single 421 // line __asm. 422 bool isAsm = Tok.is(tok::kw_asm); 423 if (SingleLineMode && !isAsm) 424 break; 425 // We're no longer in a comment. 426 InAsmComment = false; 427 if (isAsm) { 428 LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second); 429 SkippedStartOfLine = Tok.isAtStartOfLine(); 430 } 431 } else if (!InAsmComment && Tok.is(tok::r_brace)) { 432 // In MSVC mode, braces only participate in brace matching and 433 // separating the asm statements. This is an intentional 434 // departure from the Apple gcc behavior. 435 if (!BraceNesting) 436 break; 437 } 438 } 439 if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) && 440 BraceCount == (savedBraceCount + BraceNesting)) { 441 // Consume the closing brace. 442 SkippedStartOfLine = Tok.isAtStartOfLine(); 443 EndLoc = ConsumeBrace(); 444 BraceNesting--; 445 // Finish if all of the opened braces in the inline asm section were 446 // consumed. 447 if (BraceNesting == 0 && !SingleLineMode) 448 break; 449 else { 450 LBraceLocs.pop_back(); 451 TokLoc = Tok.getLocation(); 452 ++NumTokensRead; 453 continue; 454 } 455 } 456 457 // Consume the next token; make sure we don't modify the brace count etc. 458 // if we are in a comment. 459 EndLoc = TokLoc; 460 if (InAsmComment) 461 PP.Lex(Tok); 462 else { 463 // Set the token as the start of line if we skipped the original start 464 // of line token in case it was a nested brace. 465 if (SkippedStartOfLine) 466 Tok.setFlag(Token::StartOfLine); 467 AsmToks.push_back(Tok); 468 ConsumeAnyToken(); 469 } 470 TokLoc = Tok.getLocation(); 471 ++NumTokensRead; 472 SkippedStartOfLine = false; 473 } while (1); 474 475 if (BraceNesting && BraceCount != savedBraceCount) { 476 // __asm without closing brace (this can happen at EOF). 477 for (unsigned i = 0; i < BraceNesting; ++i) { 478 Diag(Tok, diag::err_expected) << tok::r_brace; 479 Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace; 480 LBraceLocs.pop_back(); 481 } 482 return StmtError(); 483 } else if (NumTokensRead == 0) { 484 // Empty __asm. 485 Diag(Tok, diag::err_expected) << tok::l_brace; 486 return StmtError(); 487 } 488 489 // Okay, prepare to use MC to parse the assembly. 490 SmallVector<StringRef, 4> ConstraintRefs; 491 SmallVector<Expr *, 4> Exprs; 492 SmallVector<StringRef, 4> ClobberRefs; 493 494 // We need an actual supported target. 495 const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple(); 496 llvm::Triple::ArchType ArchTy = TheTriple.getArch(); 497 const std::string &TT = TheTriple.getTriple(); 498 const llvm::Target *TheTarget = nullptr; 499 bool UnsupportedArch = 500 (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); 501 if (UnsupportedArch) { 502 Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); 503 } else { 504 std::string Error; 505 TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); 506 if (!TheTarget) 507 Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error; 508 } 509 510 assert(!LBraceLocs.empty() && "Should have at least one location here"); 511 512 // If we don't support assembly, or the assembly is empty, we don't 513 // need to instantiate the AsmParser, etc. 514 if (!TheTarget || AsmToks.empty()) { 515 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), 516 /*NumOutputs*/ 0, /*NumInputs*/ 0, 517 ConstraintRefs, ClobberRefs, Exprs, EndLoc); 518 } 519 520 // Expand the tokens into a string buffer. 521 SmallString<512> AsmString; 522 SmallVector<unsigned, 8> TokOffsets; 523 if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) 524 return StmtError(); 525 526 std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); 527 std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); 528 // Get the instruction descriptor. 529 std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 530 std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); 531 std::unique_ptr<llvm::MCSubtargetInfo> STI( 532 TheTarget->createMCSubtargetInfo(TT, "", "")); 533 534 llvm::SourceMgr TempSrcMgr; 535 llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); 536 MOFI->InitMCObjectFileInfo(TheTriple, llvm::Reloc::Default, 537 llvm::CodeModel::Default, Ctx); 538 std::unique_ptr<llvm::MemoryBuffer> Buffer = 539 llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); 540 541 // Tell SrcMgr about this buffer, which is what the parser will pick up. 542 TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc()); 543 544 std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); 545 std::unique_ptr<llvm::MCAsmParser> Parser( 546 createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); 547 548 // FIXME: init MCOptions from sanitizer flags here. 549 llvm::MCTargetOptions MCOptions; 550 std::unique_ptr<llvm::MCTargetAsmParser> TargetParser( 551 TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); 552 553 std::unique_ptr<llvm::MCInstPrinter> IP( 554 TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); 555 556 // Change to the Intel dialect. 557 Parser->setAssemblerDialect(1); 558 Parser->setTargetParser(*TargetParser.get()); 559 Parser->setParsingInlineAsm(true); 560 TargetParser->setParsingInlineAsm(true); 561 562 ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks, 563 TokOffsets); 564 TargetParser->setSemaCallback(&Callback); 565 TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback, 566 &Callback); 567 568 unsigned NumOutputs; 569 unsigned NumInputs; 570 std::string AsmStringIR; 571 SmallVector<std::pair<void *, bool>, 4> OpExprs; 572 SmallVector<std::string, 4> Constraints; 573 SmallVector<std::string, 4> Clobbers; 574 if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs, 575 NumInputs, OpExprs, Constraints, Clobbers, 576 MII.get(), IP.get(), Callback)) 577 return StmtError(); 578 579 // Filter out "fpsw". Clang doesn't accept it, and it always lists flags and 580 // fpsr as clobbers. 581 auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw"); 582 Clobbers.erase(End, Clobbers.end()); 583 584 // Build the vector of clobber StringRefs. 585 ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end()); 586 587 // Recast the void pointers and build the vector of constraint StringRefs. 588 unsigned NumExprs = NumOutputs + NumInputs; 589 ConstraintRefs.resize(NumExprs); 590 Exprs.resize(NumExprs); 591 for (unsigned i = 0, e = NumExprs; i != e; ++i) { 592 Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first); 593 if (!OpExpr) 594 return StmtError(); 595 596 // Need address of variable. 597 if (OpExprs[i].second) 598 OpExpr = 599 Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get(); 600 601 ConstraintRefs[i] = StringRef(Constraints[i]); 602 Exprs[i] = OpExpr; 603 } 604 605 // FIXME: We should be passing source locations for better diagnostics. 606 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR, 607 NumOutputs, NumInputs, ConstraintRefs, 608 ClobberRefs, Exprs, EndLoc); 609} 610 611/// ParseAsmStatement - Parse a GNU extended asm statement. 612/// asm-statement: 613/// gnu-asm-statement 614/// ms-asm-statement 615/// 616/// [GNU] gnu-asm-statement: 617/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' 618/// 619/// [GNU] asm-argument: 620/// asm-string-literal 621/// asm-string-literal ':' asm-operands[opt] 622/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 623/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 624/// ':' asm-clobbers 625/// 626/// [GNU] asm-clobbers: 627/// asm-string-literal 628/// asm-clobbers ',' asm-string-literal 629/// 630StmtResult Parser::ParseAsmStatement(bool &msAsm) { 631 assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); 632 SourceLocation AsmLoc = ConsumeToken(); 633 634 if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) && 635 !isTypeQualifier()) { 636 msAsm = true; 637 return ParseMicrosoftAsmStatement(AsmLoc); 638 } 639 640 DeclSpec DS(AttrFactory); 641 SourceLocation Loc = Tok.getLocation(); 642 ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); 643 644 // GNU asms accept, but warn, about type-qualifiers other than volatile. 645 if (DS.getTypeQualifiers() & DeclSpec::TQ_const) 646 Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; 647 if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) 648 Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; 649 // FIXME: Once GCC supports _Atomic, check whether it permits it here. 650 if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) 651 Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic"; 652 653 // Remember if this was a volatile asm. 654 bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; 655 if (Tok.isNot(tok::l_paren)) { 656 Diag(Tok, diag::err_expected_lparen_after) << "asm"; 657 SkipUntil(tok::r_paren, StopAtSemi); 658 return StmtError(); 659 } 660 BalancedDelimiterTracker T(*this, tok::l_paren); 661 T.consumeOpen(); 662 663 ExprResult AsmString(ParseAsmStringLiteral()); 664 665 // Check if GNU-style InlineAsm is disabled. 666 // Error on anything other than empty string. 667 if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) { 668 const auto *SL = cast<StringLiteral>(AsmString.get()); 669 if (!SL->getString().trim().empty()) 670 Diag(Loc, diag::err_gnu_inline_asm_disabled); 671 } 672 673 if (AsmString.isInvalid()) { 674 // Consume up to and including the closing paren. 675 T.skipToEnd(); 676 return StmtError(); 677 } 678 679 SmallVector<IdentifierInfo *, 4> Names; 680 ExprVector Constraints; 681 ExprVector Exprs; 682 ExprVector Clobbers; 683 684 if (Tok.is(tok::r_paren)) { 685 // We have a simple asm expression like 'asm("foo")'. 686 T.consumeClose(); 687 return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, 688 /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, 689 Constraints, Exprs, AsmString.get(), 690 Clobbers, T.getCloseLocation()); 691 } 692 693 // Parse Outputs, if present. 694 bool AteExtraColon = false; 695 if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 696 // In C++ mode, parse "::" like ": :". 697 AteExtraColon = Tok.is(tok::coloncolon); 698 ConsumeToken(); 699 700 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 701 return StmtError(); 702 } 703 704 unsigned NumOutputs = Names.size(); 705 706 // Parse Inputs, if present. 707 if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 708 // In C++ mode, parse "::" like ": :". 709 if (AteExtraColon) 710 AteExtraColon = false; 711 else { 712 AteExtraColon = Tok.is(tok::coloncolon); 713 ConsumeToken(); 714 } 715 716 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 717 return StmtError(); 718 } 719 720 assert(Names.size() == Constraints.size() && 721 Constraints.size() == Exprs.size() && "Input operand size mismatch!"); 722 723 unsigned NumInputs = Names.size() - NumOutputs; 724 725 // Parse the clobbers, if present. 726 if (AteExtraColon || Tok.is(tok::colon)) { 727 if (!AteExtraColon) 728 ConsumeToken(); 729 730 // Parse the asm-string list for clobbers if present. 731 if (Tok.isNot(tok::r_paren)) { 732 while (1) { 733 ExprResult Clobber(ParseAsmStringLiteral()); 734 735 if (Clobber.isInvalid()) 736 break; 737 738 Clobbers.push_back(Clobber.get()); 739 740 if (!TryConsumeToken(tok::comma)) 741 break; 742 } 743 } 744 } 745 746 T.consumeClose(); 747 return Actions.ActOnGCCAsmStmt( 748 AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), 749 Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); 750} 751 752/// ParseAsmOperands - Parse the asm-operands production as used by 753/// asm-statement, assuming the leading ':' token was eaten. 754/// 755/// [GNU] asm-operands: 756/// asm-operand 757/// asm-operands ',' asm-operand 758/// 759/// [GNU] asm-operand: 760/// asm-string-literal '(' expression ')' 761/// '[' identifier ']' asm-string-literal '(' expression ')' 762/// 763// 764// FIXME: Avoid unnecessary std::string trashing. 765bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, 766 SmallVectorImpl<Expr *> &Constraints, 767 SmallVectorImpl<Expr *> &Exprs) { 768 // 'asm-operands' isn't present? 769 if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) 770 return false; 771 772 while (1) { 773 // Read the [id] if present. 774 if (Tok.is(tok::l_square)) { 775 BalancedDelimiterTracker T(*this, tok::l_square); 776 T.consumeOpen(); 777 778 if (Tok.isNot(tok::identifier)) { 779 Diag(Tok, diag::err_expected) << tok::identifier; 780 SkipUntil(tok::r_paren, StopAtSemi); 781 return true; 782 } 783 784 IdentifierInfo *II = Tok.getIdentifierInfo(); 785 ConsumeToken(); 786 787 Names.push_back(II); 788 T.consumeClose(); 789 } else 790 Names.push_back(nullptr); 791 792 ExprResult Constraint(ParseAsmStringLiteral()); 793 if (Constraint.isInvalid()) { 794 SkipUntil(tok::r_paren, StopAtSemi); 795 return true; 796 } 797 Constraints.push_back(Constraint.get()); 798 799 if (Tok.isNot(tok::l_paren)) { 800 Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; 801 SkipUntil(tok::r_paren, StopAtSemi); 802 return true; 803 } 804 805 // Read the parenthesized expression. 806 BalancedDelimiterTracker T(*this, tok::l_paren); 807 T.consumeOpen(); 808 ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression()); 809 T.consumeClose(); 810 if (Res.isInvalid()) { 811 SkipUntil(tok::r_paren, StopAtSemi); 812 return true; 813 } 814 Exprs.push_back(Res.get()); 815 // Eat the comma and continue parsing if it exists. 816 if (!TryConsumeToken(tok::comma)) 817 return false; 818 } 819} 820