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