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