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