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