r210420 - Split out inline asm parsing into ParseStmtAsm.cpp

Alp Toker alp at nuanti.com
Sat Jun 7 22:40:05 PDT 2014


Author: alp
Date: Sun Jun  8 00:40:04 2014
New Revision: 210420

URL: http://llvm.org/viewvc/llvm-project?rev=210420&view=rev
Log:
Split out inline asm parsing into ParseStmtAsm.cpp

This change isolates various llvm/MC headers from the rest of the parser and
better aligns with the existing SemaStmtAsm.cpp.

No change in functionality, code move only.

Added:
    cfe/trunk/lib/Parse/ParseStmtAsm.cpp
Modified:
    cfe/trunk/lib/Parse/CMakeLists.txt
    cfe/trunk/lib/Parse/ParseStmt.cpp

Modified: cfe/trunk/lib/Parse/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/CMakeLists.txt?rev=210420&r1=210419&r2=210420&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/CMakeLists.txt (original)
+++ cfe/trunk/lib/Parse/CMakeLists.txt Sun Jun  8 00:40:04 2014
@@ -16,6 +16,7 @@ add_clang_library(clangParse
   ParseOpenMP.cpp
   ParsePragma.cpp
   ParseStmt.cpp
+  ParseStmtAsm.cpp
   ParseTemplate.cpp
   ParseTentative.cpp
   Parser.cpp

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=210420&r1=210419&r2=210420&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Sun Jun  8 00:40:04 2014
@@ -18,28 +18,12 @@
 #include "clang/Basic/Attributes.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/LoopHint.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/TypoCorrection.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -1796,718 +1780,6 @@ StmtResult Parser::ParsePragmaLoopHint(S
   return S;
 }
 
-namespace {
-  class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
-    Parser &TheParser;
-    SourceLocation AsmLoc;
-    StringRef AsmString;
-
-    /// The tokens we streamed into AsmString and handed off to MC.
-    ArrayRef<Token> AsmToks;
-
-    /// The offset of each token in AsmToks within AsmString.
-    ArrayRef<unsigned> AsmTokOffsets;
-
-  public:
-    ClangAsmParserCallback(Parser &P, SourceLocation Loc,
-                           StringRef AsmString,
-                           ArrayRef<Token> Toks,
-                           ArrayRef<unsigned> Offsets)
-      : TheParser(P), AsmLoc(Loc), AsmString(AsmString),
-        AsmToks(Toks), AsmTokOffsets(Offsets) {
-      assert(AsmToks.size() == AsmTokOffsets.size());
-    }
-
-    void *LookupInlineAsmIdentifier(StringRef &LineBuf,
-                                    llvm::InlineAsmIdentifierInfo &Info,
-                                    bool IsUnevaluatedContext) override {
-      // Collect the desired tokens.
-      SmallVector<Token, 16> LineToks;
-      const Token *FirstOrigToken = nullptr;
-      findTokensForString(LineBuf, LineToks, FirstOrigToken);
-
-      unsigned NumConsumedToks;
-      ExprResult Result =
-        TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info,
-                                       IsUnevaluatedContext);
-
-      // If we consumed the entire line, tell MC that.
-      // Also do this if we consumed nothing as a way of reporting failure.
-      if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
-        // By not modifying LineBuf, we're implicitly consuming it all.
-
-      // Otherwise, consume up to the original tokens.
-      } else {
-        assert(FirstOrigToken && "not using original tokens?");
-
-        // Since we're using original tokens, apply that offset.
-        assert(FirstOrigToken[NumConsumedToks].getLocation()
-                  == LineToks[NumConsumedToks].getLocation());
-        unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
-        unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
-
-        // The total length we've consumed is the relative offset
-        // of the last token we consumed plus its length.
-        unsigned TotalOffset = (AsmTokOffsets[LastIndex]
-                                + AsmToks[LastIndex].getLength()
-                                - AsmTokOffsets[FirstIndex]);
-        LineBuf = LineBuf.substr(0, TotalOffset);
-      }
-
-      // Initialize the "decl" with the lookup result.
-      Info.OpDecl = static_cast<void*>(Result.get());
-      return Info.OpDecl;
-    }
-
-    bool LookupInlineAsmField(StringRef Base, StringRef Member,
-                              unsigned &Offset) override {
-      return TheParser.getActions().LookupInlineAsmField(Base, Member,
-                                                         Offset, AsmLoc);
-    }
-
-    static void DiagHandlerCallback(const llvm::SMDiagnostic &D,
-                                    void *Context) {
-      ((ClangAsmParserCallback*) Context)->handleDiagnostic(D);
-    }
-
-  private:
-    /// Collect the appropriate tokens for the given string.
-    void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
-                             const Token *&FirstOrigToken) const {
-      // For now, assert that the string we're working with is a substring
-      // of what we gave to MC.  This lets us use the original tokens.
-      assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) &&
-             !std::less<const char*>()(AsmString.end(), Str.end()));
-
-      // Try to find a token whose offset matches the first token.
-      unsigned FirstCharOffset = Str.begin() - AsmString.begin();
-      const unsigned *FirstTokOffset
-        = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),
-                           FirstCharOffset);
-
-      // For now, assert that the start of the string exactly
-      // corresponds to the start of a token.
-      assert(*FirstTokOffset == FirstCharOffset);
-
-      // Use all the original tokens for this line.  (We assume the
-      // end of the line corresponds cleanly to a token break.)
-      unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
-      FirstOrigToken = &AsmToks[FirstTokIndex];
-      unsigned LastCharOffset = Str.end() - AsmString.begin();
-      for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
-        if (AsmTokOffsets[i] >= LastCharOffset) break;
-        TempToks.push_back(AsmToks[i]);
-      }
-    }
-
-    void handleDiagnostic(const llvm::SMDiagnostic &D) {
-      // Compute an offset into the inline asm buffer.
-      // FIXME: This isn't right if .macro is involved (but hopefully, no
-      // real-world code does that).
-      const llvm::SourceMgr &LSM = *D.getSourceMgr();
-      const llvm::MemoryBuffer *LBuf =
-        LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
-      unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
-
-      // Figure out which token that offset points into.
-      const unsigned *TokOffsetPtr =
-        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
-      unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
-      unsigned TokOffset = *TokOffsetPtr;
-
-      // If we come up with an answer which seems sane, use it; otherwise,
-      // just point at the __asm keyword.
-      // FIXME: Assert the answer is sane once we handle .macro correctly.
-      SourceLocation Loc = AsmLoc;
-      if (TokIndex < AsmToks.size()) {
-        const Token &Tok = AsmToks[TokIndex];
-        Loc = Tok.getLocation();
-        Loc = Loc.getLocWithOffset(Offset - TokOffset);
-      }
-      TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing)
-        << D.getMessage();
-    }
-  };
-}
-
-/// Parse an identifier in an MS-style inline assembly block.
-///
-/// \param CastInfo - a void* so that we don't have to teach Parser.h
-///   about the actual type.
-ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
-                                        unsigned &NumLineToksConsumed,
-                                        void *CastInfo,
-                                        bool IsUnevaluatedContext) {
-  llvm::InlineAsmIdentifierInfo &Info =
-    *(llvm::InlineAsmIdentifierInfo *) CastInfo;
-
-  // Push a fake token on the end so that we don't overrun the token
-  // stream.  We use ';' because it expression-parsing should never
-  // overrun it.
-  const tok::TokenKind EndOfStream = tok::semi;
-  Token EndOfStreamTok;
-  EndOfStreamTok.startToken();
-  EndOfStreamTok.setKind(EndOfStream);
-  LineToks.push_back(EndOfStreamTok);
-
-  // Also copy the current token over.
-  LineToks.push_back(Tok);
-
-  PP.EnterTokenStream(LineToks.begin(),
-                      LineToks.size(),
-                      /*disable macros*/ true,
-                      /*owns tokens*/ false);
-
-  // Clear the current token and advance to the first token in LineToks.
-  ConsumeAnyToken();
-
-  // Parse an optional scope-specifier if we're in C++.
-  CXXScopeSpec SS;
-  if (getLangOpts().CPlusPlus) {
-    ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
-  }
-
-  // Require an identifier here.
-  SourceLocation TemplateKWLoc;
-  UnqualifiedId Id;
-  bool Invalid = ParseUnqualifiedId(SS,
-                                    /*EnteringContext=*/false,
-                                    /*AllowDestructorName=*/false,
-                                    /*AllowConstructorName=*/false,
-                                    /*ObjectType=*/ ParsedType(),
-                                    TemplateKWLoc,
-                                    Id);
-
-  // Figure out how many tokens we are into LineToks.
-  unsigned LineIndex = 0;
-  if (Tok.is(EndOfStream)) {
-    LineIndex = LineToks.size() - 2;
-  } else {
-    while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
-      LineIndex++;
-      assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
-    }
-  }
-
-  // If we've run into the poison token we inserted before, or there
-  // was a parsing error, then claim the entire line.
-  if (Invalid || Tok.is(EndOfStream)) {
-    NumLineToksConsumed = LineToks.size() - 2;
-  } else {
-    // Otherwise, claim up to the start of the next token.
-    NumLineToksConsumed = LineIndex;
-  }
-
-  // Finally, restore the old parsing state by consuming all the tokens we
-  // staged before, implicitly killing off the token-lexer we pushed.
-  for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
-    ConsumeAnyToken();
-  }
-  assert(Tok.is(EndOfStream));
-  ConsumeToken();
-
-  // Leave LineToks in its original state.
-  LineToks.pop_back();
-  LineToks.pop_back();
-
-  // Perform the lookup.
-  return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
-                                           IsUnevaluatedContext);
-}
-
-/// Turn a sequence of our tokens back into a string that we can hand
-/// to the MC asm parser.
-static bool buildMSAsmString(Preprocessor &PP,
-                             SourceLocation AsmLoc,
-                             ArrayRef<Token> AsmToks,
-                             SmallVectorImpl<unsigned> &TokOffsets,
-                             SmallString<512> &Asm) {
-  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
-  // Is this the start of a new assembly statement?
-  bool isNewStatement = true;
-
-  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
-    const Token &Tok = AsmToks[i];
-
-    // Start each new statement with a newline and a tab.
-    if (!isNewStatement &&
-        (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
-      Asm += "\n\t";
-      isNewStatement = true;
-    }
-
-    // Preserve the existence of leading whitespace except at the
-    // start of a statement.
-    if (!isNewStatement && Tok.hasLeadingSpace())
-      Asm += ' ';
-
-    // Remember the offset of this token.
-    TokOffsets.push_back(Asm.size());
-
-    // Don't actually write '__asm' into the assembly stream.
-    if (Tok.is(tok::kw_asm)) {
-      // Complain about __asm at the end of the stream.
-      if (i + 1 == e) {
-        PP.Diag(AsmLoc, diag::err_asm_empty);
-        return true;
-      }
-
-      continue;
-    }
-
-    // Append the spelling of the token.
-    SmallString<32> SpellingBuffer;
-    bool SpellingInvalid = false;
-    Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
-    assert(!SpellingInvalid && "spelling was invalid after correct parse?");
-
-    // We are no longer at the start of a statement.
-    isNewStatement = false;
-  }
-
-  // Ensure that the buffer is null-terminated.
-  Asm.push_back('\0');
-  Asm.pop_back();
-
-  assert(TokOffsets.size() == AsmToks.size());
-  return false;
-}
-
-/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
-/// this routine is called to collect the tokens for an MS asm statement.
-///
-/// [MS]  ms-asm-statement:
-///         ms-asm-block
-///         ms-asm-block ms-asm-statement
-///
-/// [MS]  ms-asm-block:
-///         '__asm' ms-asm-line '\n'
-///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
-///
-/// [MS]  ms-asm-instruction-block
-///         ms-asm-line
-///         ms-asm-line '\n' ms-asm-instruction-block
-///
-StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
-  SourceManager &SrcMgr = PP.getSourceManager();
-  SourceLocation EndLoc = AsmLoc;
-  SmallVector<Token, 4> AsmToks;
-
-  bool InBraces = false;
-  unsigned short savedBraceCount = 0;
-  bool InAsmComment = false;
-  FileID FID;
-  unsigned LineNo = 0;
-  unsigned NumTokensRead = 0;
-  SourceLocation LBraceLoc;
-
-  if (Tok.is(tok::l_brace)) {
-    // Braced inline asm: consume the opening brace.
-    InBraces = true;
-    savedBraceCount = BraceCount;
-    EndLoc = LBraceLoc = ConsumeBrace();
-    ++NumTokensRead;
-  } else {
-    // Single-line inline asm; compute which line it is on.
-    std::pair<FileID, unsigned> ExpAsmLoc =
-      SrcMgr.getDecomposedExpansionLoc(EndLoc);
-    FID = ExpAsmLoc.first;
-    LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
-  }
-
-  SourceLocation TokLoc = Tok.getLocation();
-  do {
-    // If we hit EOF, we're done, period.
-    if (isEofOrEom())
-      break;
-
-    if (!InAsmComment && Tok.is(tok::semi)) {
-      // A semicolon in an asm is the start of a comment.
-      InAsmComment = true;
-      if (InBraces) {
-        // Compute which line the comment is on.
-        std::pair<FileID, unsigned> ExpSemiLoc =
-          SrcMgr.getDecomposedExpansionLoc(TokLoc);
-        FID = ExpSemiLoc.first;
-        LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
-      }
-    } else if (!InBraces || InAsmComment) {
-      // If end-of-line is significant, check whether this token is on a
-      // new line.
-      std::pair<FileID, unsigned> ExpLoc =
-        SrcMgr.getDecomposedExpansionLoc(TokLoc);
-      if (ExpLoc.first != FID ||
-          SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
-        // If this is a single-line __asm, we're done.
-        if (!InBraces)
-          break;
-        // We're no longer in a comment.
-        InAsmComment = false;
-      } else if (!InAsmComment && Tok.is(tok::r_brace)) {
-        // Single-line asm always ends when a closing brace is seen.
-        // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
-        // does MSVC do here?
-        break;
-      }
-    }
-    if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&
-        BraceCount == (savedBraceCount + 1)) {
-      // Consume the closing brace, and finish
-      EndLoc = ConsumeBrace();
-      break;
-    }
-
-    // Consume the next token; make sure we don't modify the brace count etc.
-    // if we are in a comment.
-    EndLoc = TokLoc;
-    if (InAsmComment)
-      PP.Lex(Tok);
-    else {
-      AsmToks.push_back(Tok);
-      ConsumeAnyToken();
-    }
-    TokLoc = Tok.getLocation();
-    ++NumTokensRead;
-  } while (1);
-
-  if (InBraces && BraceCount != savedBraceCount) {
-    // __asm without closing brace (this can happen at EOF).
-    Diag(Tok, diag::err_expected) << tok::r_brace;
-    Diag(LBraceLoc, diag::note_matching) << tok::l_brace;
-    return StmtError();
-  } else if (NumTokensRead == 0) {
-    // Empty __asm.
-    Diag(Tok, diag::err_expected) << tok::l_brace;
-    return StmtError();
-  }
-
-  // Okay, prepare to use MC to parse the assembly.
-  SmallVector<StringRef, 4> ConstraintRefs;
-  SmallVector<Expr*, 4> Exprs;
-  SmallVector<StringRef, 4> ClobberRefs;
-
-  // We need an actual supported target.
-  const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
-  llvm::Triple::ArchType ArchTy = TheTriple.getArch();
-  const std::string &TT = TheTriple.getTriple();
-  const llvm::Target *TheTarget = nullptr;
-  bool UnsupportedArch = (ArchTy != llvm::Triple::x86 &&
-                          ArchTy != llvm::Triple::x86_64);
-  if (UnsupportedArch) {
-    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
-  } else {
-    std::string Error;
-    TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
-    if (!TheTarget)
-      Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
-  }
-
-  // If we don't support assembly, or the assembly is empty, we don't
-  // need to instantiate the AsmParser, etc.
-  if (!TheTarget || AsmToks.empty()) {
-    return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),
-                                  /*NumOutputs*/ 0, /*NumInputs*/ 0,
-                                  ConstraintRefs, ClobberRefs, Exprs, EndLoc);
-  }
-
-  // Expand the tokens into a string buffer.
-  SmallString<512> AsmString;
-  SmallVector<unsigned, 8> TokOffsets;
-  if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
-    return StmtError();
-
-  std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
-  std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
-  // Get the instruction descriptor.
-  std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
-  std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
-  std::unique_ptr<llvm::MCSubtargetInfo> STI(
-      TheTarget->createMCSubtargetInfo(TT, "", ""));
-
-  llvm::SourceMgr TempSrcMgr;
-  llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
-  llvm::MemoryBuffer *Buffer =
-    llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
-
-  // Tell SrcMgr about this buffer, which is what the parser will pick up.
-  TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
-
-  std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
-  std::unique_ptr<llvm::MCAsmParser> Parser(
-      createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
-
-  // FIXME: init MCOptions from sanitizer flags here.
-  llvm::MCTargetOptions MCOptions;
-  std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
-      TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
-
-  std::unique_ptr<llvm::MCInstPrinter> IP(
-      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
-
-  // Change to the Intel dialect.
-  Parser->setAssemblerDialect(1);
-  Parser->setTargetParser(*TargetParser.get());
-  Parser->setParsingInlineAsm(true);
-  TargetParser->setParsingInlineAsm(true);
-
-  ClangAsmParserCallback Callback(*this, AsmLoc, AsmString,
-                                  AsmToks, TokOffsets);
-  TargetParser->setSemaCallback(&Callback);
-  TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
-                            &Callback);
-
-  unsigned NumOutputs;
-  unsigned NumInputs;
-  std::string AsmStringIR;
-  SmallVector<std::pair<void *, bool>, 4> OpExprs;
-  SmallVector<std::string, 4> Constraints;
-  SmallVector<std::string, 4> Clobbers;
-  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
-                               NumOutputs, NumInputs, OpExprs, Constraints,
-                               Clobbers, MII.get(), IP.get(), Callback))
-    return StmtError();
-
-  // Filter out "fpsw".  Clang doesn't accept it, and it always lists flags and
-  // fpsr as clobbers.
-  auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");
-  Clobbers.erase(End, Clobbers.end());
-
-  // Build the vector of clobber StringRefs.
-  unsigned NumClobbers = Clobbers.size();
-  ClobberRefs.resize(NumClobbers);
-  for (unsigned i = 0; i != NumClobbers; ++i)
-    ClobberRefs[i] = StringRef(Clobbers[i]);
-
-  // Recast the void pointers and build the vector of constraint StringRefs.
-  unsigned NumExprs = NumOutputs + NumInputs;
-  ConstraintRefs.resize(NumExprs);
-  Exprs.resize(NumExprs);
-  for (unsigned i = 0, e = NumExprs; i != e; ++i) {
-    Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
-    if (!OpExpr)
-      return StmtError();
-
-    // Need address of variable.
-    if (OpExprs[i].second)
-      OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr)
-        .get();
-
-    ConstraintRefs[i] = StringRef(Constraints[i]);
-    Exprs[i] = OpExpr;
-  }
-
-  // FIXME: We should be passing source locations for better diagnostics.
-  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,
-                                NumOutputs, NumInputs,
-                                ConstraintRefs, ClobberRefs, Exprs, EndLoc);
-}
-
-/// ParseAsmStatement - Parse a GNU extended asm statement.
-///       asm-statement:
-///         gnu-asm-statement
-///         ms-asm-statement
-///
-/// [GNU] gnu-asm-statement:
-///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'
-///
-/// [GNU] asm-argument:
-///         asm-string-literal
-///         asm-string-literal ':' asm-operands[opt]
-///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
-///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
-///                 ':' asm-clobbers
-///
-/// [GNU] asm-clobbers:
-///         asm-string-literal
-///         asm-clobbers ',' asm-string-literal
-///
-StmtResult Parser::ParseAsmStatement(bool &msAsm) {
-  assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
-  SourceLocation AsmLoc = ConsumeToken();
-
-  if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
-      !isTypeQualifier()) {
-    msAsm = true;
-    return ParseMicrosoftAsmStatement(AsmLoc);
-  }
-  DeclSpec DS(AttrFactory);
-  SourceLocation Loc = Tok.getLocation();
-  ParseTypeQualifierListOpt(DS, true, false);
-
-  // GNU asms accept, but warn, about type-qualifiers other than volatile.
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
-  // FIXME: Once GCC supports _Atomic, check whether it permits it here.
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
-
-  // Remember if this was a volatile asm.
-  bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
-  if (Tok.isNot(tok::l_paren)) {
-    Diag(Tok, diag::err_expected_lparen_after) << "asm";
-    SkipUntil(tok::r_paren, StopAtSemi);
-    return StmtError();
-  }
-  BalancedDelimiterTracker T(*this, tok::l_paren);
-  T.consumeOpen();
-
-  ExprResult AsmString(ParseAsmStringLiteral());
-  if (AsmString.isInvalid()) {
-    // Consume up to and including the closing paren.
-    T.skipToEnd();
-    return StmtError();
-  }
-
-  SmallVector<IdentifierInfo *, 4> Names;
-  ExprVector Constraints;
-  ExprVector Exprs;
-  ExprVector Clobbers;
-
-  if (Tok.is(tok::r_paren)) {
-    // We have a simple asm expression like 'asm("foo")'.
-    T.consumeClose();
-    return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
-                                   /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
-                                   Constraints, Exprs, AsmString.get(),
-                                   Clobbers, T.getCloseLocation());
-  }
-
-  // Parse Outputs, if present.
-  bool AteExtraColon = false;
-  if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
-    // In C++ mode, parse "::" like ": :".
-    AteExtraColon = Tok.is(tok::coloncolon);
-    ConsumeToken();
-
-    if (!AteExtraColon &&
-        ParseAsmOperandsOpt(Names, Constraints, Exprs))
-      return StmtError();
-  }
-
-  unsigned NumOutputs = Names.size();
-
-  // Parse Inputs, if present.
-  if (AteExtraColon ||
-      Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
-    // In C++ mode, parse "::" like ": :".
-    if (AteExtraColon)
-      AteExtraColon = false;
-    else {
-      AteExtraColon = Tok.is(tok::coloncolon);
-      ConsumeToken();
-    }
-
-    if (!AteExtraColon &&
-        ParseAsmOperandsOpt(Names, Constraints, Exprs))
-      return StmtError();
-  }
-
-  assert(Names.size() == Constraints.size() &&
-         Constraints.size() == Exprs.size() &&
-         "Input operand size mismatch!");
-
-  unsigned NumInputs = Names.size() - NumOutputs;
-
-  // Parse the clobbers, if present.
-  if (AteExtraColon || Tok.is(tok::colon)) {
-    if (!AteExtraColon)
-      ConsumeToken();
-
-    // Parse the asm-string list for clobbers if present.
-    if (Tok.isNot(tok::r_paren)) {
-      while (1) {
-        ExprResult Clobber(ParseAsmStringLiteral());
-
-        if (Clobber.isInvalid())
-          break;
-
-        Clobbers.push_back(Clobber.get());
-
-        if (!TryConsumeToken(tok::comma))
-          break;
-      }
-    }
-  }
-
-  T.consumeClose();
-  return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,
-                                 NumInputs, Names.data(), Constraints, Exprs,
-                                 AsmString.get(), Clobbers,
-                                 T.getCloseLocation());
-}
-
-/// ParseAsmOperands - Parse the asm-operands production as used by
-/// asm-statement, assuming the leading ':' token was eaten.
-///
-/// [GNU] asm-operands:
-///         asm-operand
-///         asm-operands ',' asm-operand
-///
-/// [GNU] asm-operand:
-///         asm-string-literal '(' expression ')'
-///         '[' identifier ']' asm-string-literal '(' expression ')'
-///
-//
-// FIXME: Avoid unnecessary std::string trashing.
-bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
-                                 SmallVectorImpl<Expr *> &Constraints,
-                                 SmallVectorImpl<Expr *> &Exprs) {
-  // 'asm-operands' isn't present?
-  if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
-    return false;
-
-  while (1) {
-    // Read the [id] if present.
-    if (Tok.is(tok::l_square)) {
-      BalancedDelimiterTracker T(*this, tok::l_square);
-      T.consumeOpen();
-
-      if (Tok.isNot(tok::identifier)) {
-        Diag(Tok, diag::err_expected) << tok::identifier;
-        SkipUntil(tok::r_paren, StopAtSemi);
-        return true;
-      }
-
-      IdentifierInfo *II = Tok.getIdentifierInfo();
-      ConsumeToken();
-
-      Names.push_back(II);
-      T.consumeClose();
-    } else
-      Names.push_back(nullptr);
-
-    ExprResult Constraint(ParseAsmStringLiteral());
-    if (Constraint.isInvalid()) {
-        SkipUntil(tok::r_paren, StopAtSemi);
-        return true;
-    }
-    Constraints.push_back(Constraint.get());
-
-    if (Tok.isNot(tok::l_paren)) {
-      Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
-      SkipUntil(tok::r_paren, StopAtSemi);
-      return true;
-    }
-
-    // Read the parenthesized expression.
-    BalancedDelimiterTracker T(*this, tok::l_paren);
-    T.consumeOpen();
-    ExprResult Res(ParseExpression());
-    T.consumeClose();
-    if (Res.isInvalid()) {
-      SkipUntil(tok::r_paren, StopAtSemi);
-      return true;
-    }
-    Exprs.push_back(Res.get());
-    // Eat the comma and continue parsing if it exists.
-    if (!TryConsumeToken(tok::comma))
-      return false;
-  }
-}
-
 Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
   assert(Tok.is(tok::l_brace));
   SourceLocation LBraceLoc = Tok.getLocation();

Added: cfe/trunk/lib/Parse/ParseStmtAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=210420&view=auto
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmtAsm.cpp (added)
+++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp Sun Jun  8 00:40:04 2014
@@ -0,0 +1,732 @@
+//===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing for GCC and Microsoft inline assembly. 
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+using namespace clang;
+
+namespace {
+class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
+  Parser &TheParser;
+  SourceLocation AsmLoc;
+  StringRef AsmString;
+
+  /// The tokens we streamed into AsmString and handed off to MC.
+  ArrayRef<Token> AsmToks;
+
+  /// The offset of each token in AsmToks within AsmString.
+  ArrayRef<unsigned> AsmTokOffsets;
+
+public:
+  ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString,
+                         ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets)
+      : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
+        AsmTokOffsets(Offsets) {
+    assert(AsmToks.size() == AsmTokOffsets.size());
+  }
+
+  void *LookupInlineAsmIdentifier(StringRef &LineBuf,
+                                  llvm::InlineAsmIdentifierInfo &Info,
+                                  bool IsUnevaluatedContext) override {
+    // Collect the desired tokens.
+    SmallVector<Token, 16> LineToks;
+    const Token *FirstOrigToken = nullptr;
+    findTokensForString(LineBuf, LineToks, FirstOrigToken);
+
+    unsigned NumConsumedToks;
+    ExprResult Result = TheParser.ParseMSAsmIdentifier(
+        LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
+
+    // If we consumed the entire line, tell MC that.
+    // Also do this if we consumed nothing as a way of reporting failure.
+    if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
+      // By not modifying LineBuf, we're implicitly consuming it all.
+
+      // Otherwise, consume up to the original tokens.
+    } else {
+      assert(FirstOrigToken && "not using original tokens?");
+
+      // Since we're using original tokens, apply that offset.
+      assert(FirstOrigToken[NumConsumedToks].getLocation() ==
+             LineToks[NumConsumedToks].getLocation());
+      unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
+      unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
+
+      // The total length we've consumed is the relative offset
+      // of the last token we consumed plus its length.
+      unsigned TotalOffset =
+          (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
+           AsmTokOffsets[FirstIndex]);
+      LineBuf = LineBuf.substr(0, TotalOffset);
+    }
+
+    // Initialize the "decl" with the lookup result.
+    Info.OpDecl = static_cast<void *>(Result.get());
+    return Info.OpDecl;
+  }
+
+  bool LookupInlineAsmField(StringRef Base, StringRef Member,
+                            unsigned &Offset) override {
+    return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
+                                                       AsmLoc);
+  }
+
+  static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) {
+    ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
+  }
+
+private:
+  /// Collect the appropriate tokens for the given string.
+  void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
+                           const Token *&FirstOrigToken) const {
+    // For now, assert that the string we're working with is a substring
+    // of what we gave to MC.  This lets us use the original tokens.
+    assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
+           !std::less<const char *>()(AsmString.end(), Str.end()));
+
+    // Try to find a token whose offset matches the first token.
+    unsigned FirstCharOffset = Str.begin() - AsmString.begin();
+    const unsigned *FirstTokOffset = std::lower_bound(
+        AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
+
+    // For now, assert that the start of the string exactly
+    // corresponds to the start of a token.
+    assert(*FirstTokOffset == FirstCharOffset);
+
+    // Use all the original tokens for this line.  (We assume the
+    // end of the line corresponds cleanly to a token break.)
+    unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
+    FirstOrigToken = &AsmToks[FirstTokIndex];
+    unsigned LastCharOffset = Str.end() - AsmString.begin();
+    for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
+      if (AsmTokOffsets[i] >= LastCharOffset)
+        break;
+      TempToks.push_back(AsmToks[i]);
+    }
+  }
+
+  void handleDiagnostic(const llvm::SMDiagnostic &D) {
+    // Compute an offset into the inline asm buffer.
+    // FIXME: This isn't right if .macro is involved (but hopefully, no
+    // real-world code does that).
+    const llvm::SourceMgr &LSM = *D.getSourceMgr();
+    const llvm::MemoryBuffer *LBuf =
+        LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+    unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+
+    // Figure out which token that offset points into.
+    const unsigned *TokOffsetPtr =
+        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
+    unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
+    unsigned TokOffset = *TokOffsetPtr;
+
+    // If we come up with an answer which seems sane, use it; otherwise,
+    // just point at the __asm keyword.
+    // FIXME: Assert the answer is sane once we handle .macro correctly.
+    SourceLocation Loc = AsmLoc;
+    if (TokIndex < AsmToks.size()) {
+      const Token &Tok = AsmToks[TokIndex];
+      Loc = Tok.getLocation();
+      Loc = Loc.getLocWithOffset(Offset - TokOffset);
+    }
+    TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+  }
+};
+}
+
+/// Parse an identifier in an MS-style inline assembly block.
+///
+/// \param CastInfo - a void* so that we don't have to teach Parser.h
+///   about the actual type.
+ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
+                                        unsigned &NumLineToksConsumed,
+                                        void *CastInfo,
+                                        bool IsUnevaluatedContext) {
+  llvm::InlineAsmIdentifierInfo &Info =
+      *(llvm::InlineAsmIdentifierInfo *)CastInfo;
+
+  // Push a fake token on the end so that we don't overrun the token
+  // stream.  We use ';' because it expression-parsing should never
+  // overrun it.
+  const tok::TokenKind EndOfStream = tok::semi;
+  Token EndOfStreamTok;
+  EndOfStreamTok.startToken();
+  EndOfStreamTok.setKind(EndOfStream);
+  LineToks.push_back(EndOfStreamTok);
+
+  // Also copy the current token over.
+  LineToks.push_back(Tok);
+
+  PP.EnterTokenStream(LineToks.begin(), LineToks.size(),
+                      /*disable macros*/ true,
+                      /*owns tokens*/ false);
+
+  // Clear the current token and advance to the first token in LineToks.
+  ConsumeAnyToken();
+
+  // Parse an optional scope-specifier if we're in C++.
+  CXXScopeSpec SS;
+  if (getLangOpts().CPlusPlus) {
+    ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+  }
+
+  // Require an identifier here.
+  SourceLocation TemplateKWLoc;
+  UnqualifiedId Id;
+  bool Invalid =
+      ParseUnqualifiedId(SS,
+                         /*EnteringContext=*/false,
+                         /*AllowDestructorName=*/false,
+                         /*AllowConstructorName=*/false,
+                         /*ObjectType=*/ParsedType(), TemplateKWLoc, Id);
+
+  // Figure out how many tokens we are into LineToks.
+  unsigned LineIndex = 0;
+  if (Tok.is(EndOfStream)) {
+    LineIndex = LineToks.size() - 2;
+  } else {
+    while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
+      LineIndex++;
+      assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
+    }
+  }
+
+  // If we've run into the poison token we inserted before, or there
+  // was a parsing error, then claim the entire line.
+  if (Invalid || Tok.is(EndOfStream)) {
+    NumLineToksConsumed = LineToks.size() - 2;
+  } else {
+    // Otherwise, claim up to the start of the next token.
+    NumLineToksConsumed = LineIndex;
+  }
+
+  // Finally, restore the old parsing state by consuming all the tokens we
+  // staged before, implicitly killing off the token-lexer we pushed.
+  for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
+    ConsumeAnyToken();
+  }
+  assert(Tok.is(EndOfStream));
+  ConsumeToken();
+
+  // Leave LineToks in its original state.
+  LineToks.pop_back();
+  LineToks.pop_back();
+
+  // Perform the lookup.
+  return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
+                                           IsUnevaluatedContext);
+}
+
+/// Turn a sequence of our tokens back into a string that we can hand
+/// to the MC asm parser.
+static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,
+                             ArrayRef<Token> AsmToks,
+                             SmallVectorImpl<unsigned> &TokOffsets,
+                             SmallString<512> &Asm) {
+  assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+  // Is this the start of a new assembly statement?
+  bool isNewStatement = true;
+
+  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+    const Token &Tok = AsmToks[i];
+
+    // Start each new statement with a newline and a tab.
+    if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
+      Asm += "\n\t";
+      isNewStatement = true;
+    }
+
+    // Preserve the existence of leading whitespace except at the
+    // start of a statement.
+    if (!isNewStatement && Tok.hasLeadingSpace())
+      Asm += ' ';
+
+    // Remember the offset of this token.
+    TokOffsets.push_back(Asm.size());
+
+    // Don't actually write '__asm' into the assembly stream.
+    if (Tok.is(tok::kw_asm)) {
+      // Complain about __asm at the end of the stream.
+      if (i + 1 == e) {
+        PP.Diag(AsmLoc, diag::err_asm_empty);
+        return true;
+      }
+
+      continue;
+    }
+
+    // Append the spelling of the token.
+    SmallString<32> SpellingBuffer;
+    bool SpellingInvalid = false;
+    Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
+    assert(!SpellingInvalid && "spelling was invalid after correct parse?");
+
+    // We are no longer at the start of a statement.
+    isNewStatement = false;
+  }
+
+  // Ensure that the buffer is null-terminated.
+  Asm.push_back('\0');
+  Asm.pop_back();
+
+  assert(TokOffsets.size() == AsmToks.size());
+  return false;
+}
+
+/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
+/// this routine is called to collect the tokens for an MS asm statement.
+///
+/// [MS]  ms-asm-statement:
+///         ms-asm-block
+///         ms-asm-block ms-asm-statement
+///
+/// [MS]  ms-asm-block:
+///         '__asm' ms-asm-line '\n'
+///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
+///
+/// [MS]  ms-asm-instruction-block
+///         ms-asm-line
+///         ms-asm-line '\n' ms-asm-instruction-block
+///
+StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
+  SourceManager &SrcMgr = PP.getSourceManager();
+  SourceLocation EndLoc = AsmLoc;
+  SmallVector<Token, 4> AsmToks;
+
+  bool InBraces = false;
+  unsigned short savedBraceCount = 0;
+  bool InAsmComment = false;
+  FileID FID;
+  unsigned LineNo = 0;
+  unsigned NumTokensRead = 0;
+  SourceLocation LBraceLoc;
+
+  if (Tok.is(tok::l_brace)) {
+    // Braced inline asm: consume the opening brace.
+    InBraces = true;
+    savedBraceCount = BraceCount;
+    EndLoc = LBraceLoc = ConsumeBrace();
+    ++NumTokensRead;
+  } else {
+    // Single-line inline asm; compute which line it is on.
+    std::pair<FileID, unsigned> ExpAsmLoc =
+        SrcMgr.getDecomposedExpansionLoc(EndLoc);
+    FID = ExpAsmLoc.first;
+    LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
+  }
+
+  SourceLocation TokLoc = Tok.getLocation();
+  do {
+    // If we hit EOF, we're done, period.
+    if (isEofOrEom())
+      break;
+
+    if (!InAsmComment && Tok.is(tok::semi)) {
+      // A semicolon in an asm is the start of a comment.
+      InAsmComment = true;
+      if (InBraces) {
+        // Compute which line the comment is on.
+        std::pair<FileID, unsigned> ExpSemiLoc =
+            SrcMgr.getDecomposedExpansionLoc(TokLoc);
+        FID = ExpSemiLoc.first;
+        LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
+      }
+    } else if (!InBraces || InAsmComment) {
+      // If end-of-line is significant, check whether this token is on a
+      // new line.
+      std::pair<FileID, unsigned> ExpLoc =
+          SrcMgr.getDecomposedExpansionLoc(TokLoc);
+      if (ExpLoc.first != FID ||
+          SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
+        // If this is a single-line __asm, we're done.
+        if (!InBraces)
+          break;
+        // We're no longer in a comment.
+        InAsmComment = false;
+      } else if (!InAsmComment && Tok.is(tok::r_brace)) {
+        // Single-line asm always ends when a closing brace is seen.
+        // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
+        // does MSVC do here?
+        break;
+      }
+    }
+    if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&
+        BraceCount == (savedBraceCount + 1)) {
+      // Consume the closing brace, and finish
+      EndLoc = ConsumeBrace();
+      break;
+    }
+
+    // Consume the next token; make sure we don't modify the brace count etc.
+    // if we are in a comment.
+    EndLoc = TokLoc;
+    if (InAsmComment)
+      PP.Lex(Tok);
+    else {
+      AsmToks.push_back(Tok);
+      ConsumeAnyToken();
+    }
+    TokLoc = Tok.getLocation();
+    ++NumTokensRead;
+  } while (1);
+
+  if (InBraces && BraceCount != savedBraceCount) {
+    // __asm without closing brace (this can happen at EOF).
+    Diag(Tok, diag::err_expected) << tok::r_brace;
+    Diag(LBraceLoc, diag::note_matching) << tok::l_brace;
+    return StmtError();
+  } else if (NumTokensRead == 0) {
+    // Empty __asm.
+    Diag(Tok, diag::err_expected) << tok::l_brace;
+    return StmtError();
+  }
+
+  // Okay, prepare to use MC to parse the assembly.
+  SmallVector<StringRef, 4> ConstraintRefs;
+  SmallVector<Expr *, 4> Exprs;
+  SmallVector<StringRef, 4> ClobberRefs;
+
+  // We need an actual supported target.
+  const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
+  llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+  const std::string &TT = TheTriple.getTriple();
+  const llvm::Target *TheTarget = nullptr;
+  bool UnsupportedArch =
+      (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
+  if (UnsupportedArch) {
+    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
+  } else {
+    std::string Error;
+    TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
+    if (!TheTarget)
+      Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
+  }
+
+  // If we don't support assembly, or the assembly is empty, we don't
+  // need to instantiate the AsmParser, etc.
+  if (!TheTarget || AsmToks.empty()) {
+    return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),
+                                  /*NumOutputs*/ 0, /*NumInputs*/ 0,
+                                  ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+  }
+
+  // Expand the tokens into a string buffer.
+  SmallString<512> AsmString;
+  SmallVector<unsigned, 8> TokOffsets;
+  if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
+    return StmtError();
+
+  std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+  std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
+  // Get the instruction descriptor.
+  std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+  std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+  std::unique_ptr<llvm::MCSubtargetInfo> STI(
+      TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+  llvm::SourceMgr TempSrcMgr;
+  llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
+  llvm::MemoryBuffer *Buffer =
+      llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
+
+  // Tell SrcMgr about this buffer, which is what the parser will pick up.
+  TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+  std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
+  std::unique_ptr<llvm::MCAsmParser> Parser(
+      createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
+
+  // FIXME: init MCOptions from sanitizer flags here.
+  llvm::MCTargetOptions MCOptions;
+  std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
+      TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
+
+  std::unique_ptr<llvm::MCInstPrinter> IP(
+      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
+
+  // Change to the Intel dialect.
+  Parser->setAssemblerDialect(1);
+  Parser->setTargetParser(*TargetParser.get());
+  Parser->setParsingInlineAsm(true);
+  TargetParser->setParsingInlineAsm(true);
+
+  ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,
+                                  TokOffsets);
+  TargetParser->setSemaCallback(&Callback);
+  TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
+                            &Callback);
+
+  unsigned NumOutputs;
+  unsigned NumInputs;
+  std::string AsmStringIR;
+  SmallVector<std::pair<void *, bool>, 4> OpExprs;
+  SmallVector<std::string, 4> Constraints;
+  SmallVector<std::string, 4> Clobbers;
+  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
+                               NumInputs, OpExprs, Constraints, Clobbers,
+                               MII.get(), IP.get(), Callback))
+    return StmtError();
+
+  // Filter out "fpsw".  Clang doesn't accept it, and it always lists flags and
+  // fpsr as clobbers.
+  auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");
+  Clobbers.erase(End, Clobbers.end());
+
+  // Build the vector of clobber StringRefs.
+  unsigned NumClobbers = Clobbers.size();
+  ClobberRefs.resize(NumClobbers);
+  for (unsigned i = 0; i != NumClobbers; ++i)
+    ClobberRefs[i] = StringRef(Clobbers[i]);
+
+  // Recast the void pointers and build the vector of constraint StringRefs.
+  unsigned NumExprs = NumOutputs + NumInputs;
+  ConstraintRefs.resize(NumExprs);
+  Exprs.resize(NumExprs);
+  for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+    Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
+    if (!OpExpr)
+      return StmtError();
+
+    // Need address of variable.
+    if (OpExprs[i].second)
+      OpExpr =
+          Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
+
+    ConstraintRefs[i] = StringRef(Constraints[i]);
+    Exprs[i] = OpExpr;
+  }
+
+  // FIXME: We should be passing source locations for better diagnostics.
+  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,
+                                NumOutputs, NumInputs, ConstraintRefs,
+                                ClobberRefs, Exprs, EndLoc);
+}
+
+/// ParseAsmStatement - Parse a GNU extended asm statement.
+///       asm-statement:
+///         gnu-asm-statement
+///         ms-asm-statement
+///
+/// [GNU] gnu-asm-statement:
+///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'
+///
+/// [GNU] asm-argument:
+///         asm-string-literal
+///         asm-string-literal ':' asm-operands[opt]
+///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+///                 ':' asm-clobbers
+///
+/// [GNU] asm-clobbers:
+///         asm-string-literal
+///         asm-clobbers ',' asm-string-literal
+///
+StmtResult Parser::ParseAsmStatement(bool &msAsm) {
+  assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
+  SourceLocation AsmLoc = ConsumeToken();
+
+  if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
+      !isTypeQualifier()) {
+    msAsm = true;
+    return ParseMicrosoftAsmStatement(AsmLoc);
+  }
+  DeclSpec DS(AttrFactory);
+  SourceLocation Loc = Tok.getLocation();
+  ParseTypeQualifierListOpt(DS, true, false);
+
+  // GNU asms accept, but warn, about type-qualifiers other than volatile.
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+  // FIXME: Once GCC supports _Atomic, check whether it permits it here.
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
+
+  // Remember if this was a volatile asm.
+  bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok, diag::err_expected_lparen_after) << "asm";
+    SkipUntil(tok::r_paren, StopAtSemi);
+    return StmtError();
+  }
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  T.consumeOpen();
+
+  ExprResult AsmString(ParseAsmStringLiteral());
+  if (AsmString.isInvalid()) {
+    // Consume up to and including the closing paren.
+    T.skipToEnd();
+    return StmtError();
+  }
+
+  SmallVector<IdentifierInfo *, 4> Names;
+  ExprVector Constraints;
+  ExprVector Exprs;
+  ExprVector Clobbers;
+
+  if (Tok.is(tok::r_paren)) {
+    // We have a simple asm expression like 'asm("foo")'.
+    T.consumeClose();
+    return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
+                                   /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
+                                   Constraints, Exprs, AsmString.get(),
+                                   Clobbers, T.getCloseLocation());
+  }
+
+  // Parse Outputs, if present.
+  bool AteExtraColon = false;
+  if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+    // In C++ mode, parse "::" like ": :".
+    AteExtraColon = Tok.is(tok::coloncolon);
+    ConsumeToken();
+
+    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
+      return StmtError();
+  }
+
+  unsigned NumOutputs = Names.size();
+
+  // Parse Inputs, if present.
+  if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+    // In C++ mode, parse "::" like ": :".
+    if (AteExtraColon)
+      AteExtraColon = false;
+    else {
+      AteExtraColon = Tok.is(tok::coloncolon);
+      ConsumeToken();
+    }
+
+    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
+      return StmtError();
+  }
+
+  assert(Names.size() == Constraints.size() &&
+         Constraints.size() == Exprs.size() && "Input operand size mismatch!");
+
+  unsigned NumInputs = Names.size() - NumOutputs;
+
+  // Parse the clobbers, if present.
+  if (AteExtraColon || Tok.is(tok::colon)) {
+    if (!AteExtraColon)
+      ConsumeToken();
+
+    // Parse the asm-string list for clobbers if present.
+    if (Tok.isNot(tok::r_paren)) {
+      while (1) {
+        ExprResult Clobber(ParseAsmStringLiteral());
+
+        if (Clobber.isInvalid())
+          break;
+
+        Clobbers.push_back(Clobber.get());
+
+        if (!TryConsumeToken(tok::comma))
+          break;
+      }
+    }
+  }
+
+  T.consumeClose();
+  return Actions.ActOnGCCAsmStmt(
+      AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
+      Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
+}
+
+/// ParseAsmOperands - Parse the asm-operands production as used by
+/// asm-statement, assuming the leading ':' token was eaten.
+///
+/// [GNU] asm-operands:
+///         asm-operand
+///         asm-operands ',' asm-operand
+///
+/// [GNU] asm-operand:
+///         asm-string-literal '(' expression ')'
+///         '[' identifier ']' asm-string-literal '(' expression ')'
+///
+//
+// FIXME: Avoid unnecessary std::string trashing.
+bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
+                                 SmallVectorImpl<Expr *> &Constraints,
+                                 SmallVectorImpl<Expr *> &Exprs) {
+  // 'asm-operands' isn't present?
+  if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
+    return false;
+
+  while (1) {
+    // Read the [id] if present.
+    if (Tok.is(tok::l_square)) {
+      BalancedDelimiterTracker T(*this, tok::l_square);
+      T.consumeOpen();
+
+      if (Tok.isNot(tok::identifier)) {
+        Diag(Tok, diag::err_expected) << tok::identifier;
+        SkipUntil(tok::r_paren, StopAtSemi);
+        return true;
+      }
+
+      IdentifierInfo *II = Tok.getIdentifierInfo();
+      ConsumeToken();
+
+      Names.push_back(II);
+      T.consumeClose();
+    } else
+      Names.push_back(nullptr);
+
+    ExprResult Constraint(ParseAsmStringLiteral());
+    if (Constraint.isInvalid()) {
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return true;
+    }
+    Constraints.push_back(Constraint.get());
+
+    if (Tok.isNot(tok::l_paren)) {
+      Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return true;
+    }
+
+    // Read the parenthesized expression.
+    BalancedDelimiterTracker T(*this, tok::l_paren);
+    T.consumeOpen();
+    ExprResult Res(ParseExpression());
+    T.consumeClose();
+    if (Res.isInvalid()) {
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return true;
+    }
+    Exprs.push_back(Res.get());
+    // Eat the comma and continue parsing if it exists.
+    if (!TryConsumeToken(tok::comma))
+      return false;
+  }
+}





More information about the cfe-commits mailing list