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