brintos

brintos / llvm-project-archived public Read only

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