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