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