10b57cec5SDimitry Andric //===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements parsing for GCC and Microsoft inline assembly.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
140b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h"
150b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
16349cc55cSDimitry Andric #include "clang/Parse/Parser.h"
170b57cec5SDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCAsmParser.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
280b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
290b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
31349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
320b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h"
330b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
340b57cec5SDimitry Andric using namespace clang;
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric namespace {
370b57cec5SDimitry Andric class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
380b57cec5SDimitry Andric Parser &TheParser;
390b57cec5SDimitry Andric SourceLocation AsmLoc;
400b57cec5SDimitry Andric StringRef AsmString;
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric /// The tokens we streamed into AsmString and handed off to MC.
430b57cec5SDimitry Andric ArrayRef<Token> AsmToks;
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric /// The offset of each token in AsmToks within AsmString.
460b57cec5SDimitry Andric ArrayRef<unsigned> AsmTokOffsets;
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric public:
ClangAsmParserCallback(Parser & P,SourceLocation Loc,StringRef AsmString,ArrayRef<Token> Toks,ArrayRef<unsigned> Offsets)490b57cec5SDimitry Andric ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString,
500b57cec5SDimitry Andric ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets)
510b57cec5SDimitry Andric : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
520b57cec5SDimitry Andric AsmTokOffsets(Offsets) {
530b57cec5SDimitry Andric assert(AsmToks.size() == AsmTokOffsets.size());
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric void LookupInlineAsmIdentifier(StringRef &LineBuf,
570b57cec5SDimitry Andric llvm::InlineAsmIdentifierInfo &Info,
580b57cec5SDimitry Andric bool IsUnevaluatedContext) override;
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
610b57cec5SDimitry Andric llvm::SMLoc Location,
620b57cec5SDimitry Andric bool Create) override;
630b57cec5SDimitry Andric
LookupInlineAsmField(StringRef Base,StringRef Member,unsigned & Offset)640b57cec5SDimitry Andric bool LookupInlineAsmField(StringRef Base, StringRef Member,
650b57cec5SDimitry Andric unsigned &Offset) override {
660b57cec5SDimitry Andric return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
670b57cec5SDimitry Andric AsmLoc);
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
DiagHandlerCallback(const llvm::SMDiagnostic & D,void * Context)700b57cec5SDimitry Andric static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) {
710b57cec5SDimitry Andric ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric private:
750b57cec5SDimitry Andric /// Collect the appropriate tokens for the given string.
760b57cec5SDimitry Andric void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
770b57cec5SDimitry Andric const Token *&FirstOrigToken) const;
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric SourceLocation translateLocation(const llvm::SourceMgr &LSM,
800b57cec5SDimitry Andric llvm::SMLoc SMLoc);
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric void handleDiagnostic(const llvm::SMDiagnostic &D);
830b57cec5SDimitry Andric };
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric
LookupInlineAsmIdentifier(StringRef & LineBuf,llvm::InlineAsmIdentifierInfo & Info,bool IsUnevaluatedContext)860b57cec5SDimitry Andric void ClangAsmParserCallback::LookupInlineAsmIdentifier(
870b57cec5SDimitry Andric StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info,
880b57cec5SDimitry Andric bool IsUnevaluatedContext) {
890b57cec5SDimitry Andric // Collect the desired tokens.
900b57cec5SDimitry Andric SmallVector<Token, 16> LineToks;
910b57cec5SDimitry Andric const Token *FirstOrigToken = nullptr;
920b57cec5SDimitry Andric findTokensForString(LineBuf, LineToks, FirstOrigToken);
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric unsigned NumConsumedToks;
950b57cec5SDimitry Andric ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks,
960b57cec5SDimitry Andric IsUnevaluatedContext);
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric // If we consumed the entire line, tell MC that.
990b57cec5SDimitry Andric // Also do this if we consumed nothing as a way of reporting failure.
1000b57cec5SDimitry Andric if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
1010b57cec5SDimitry Andric // By not modifying LineBuf, we're implicitly consuming it all.
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric // Otherwise, consume up to the original tokens.
1040b57cec5SDimitry Andric } else {
1050b57cec5SDimitry Andric assert(FirstOrigToken && "not using original tokens?");
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric // Since we're using original tokens, apply that offset.
1080b57cec5SDimitry Andric assert(FirstOrigToken[NumConsumedToks].getLocation() ==
1090b57cec5SDimitry Andric LineToks[NumConsumedToks].getLocation());
1100b57cec5SDimitry Andric unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
1110b57cec5SDimitry Andric unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric // The total length we've consumed is the relative offset
1140b57cec5SDimitry Andric // of the last token we consumed plus its length.
1150b57cec5SDimitry Andric unsigned TotalOffset =
1160b57cec5SDimitry Andric (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
1170b57cec5SDimitry Andric AsmTokOffsets[FirstIndex]);
1180b57cec5SDimitry Andric LineBuf = LineBuf.substr(0, TotalOffset);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric // Initialize Info with the lookup result.
1220b57cec5SDimitry Andric if (!Result.isUsable())
1230b57cec5SDimitry Andric return;
1240b57cec5SDimitry Andric TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
LookupInlineAsmLabel(StringRef Identifier,llvm::SourceMgr & LSM,llvm::SMLoc Location,bool Create)1270b57cec5SDimitry Andric StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier,
1280b57cec5SDimitry Andric llvm::SourceMgr &LSM,
1290b57cec5SDimitry Andric llvm::SMLoc Location,
1300b57cec5SDimitry Andric bool Create) {
1310b57cec5SDimitry Andric SourceLocation Loc = translateLocation(LSM, Location);
1320b57cec5SDimitry Andric LabelDecl *Label =
1330b57cec5SDimitry Andric TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
1340b57cec5SDimitry Andric return Label->getMSAsmLabel();
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric
findTokensForString(StringRef Str,SmallVectorImpl<Token> & TempToks,const Token * & FirstOrigToken) const1370b57cec5SDimitry Andric void ClangAsmParserCallback::findTokensForString(
1380b57cec5SDimitry Andric StringRef Str, SmallVectorImpl<Token> &TempToks,
1390b57cec5SDimitry Andric const Token *&FirstOrigToken) const {
1400b57cec5SDimitry Andric // For now, assert that the string we're working with is a substring
1410b57cec5SDimitry Andric // of what we gave to MC. This lets us use the original tokens.
1420b57cec5SDimitry Andric assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
1430b57cec5SDimitry Andric !std::less<const char *>()(AsmString.end(), Str.end()));
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric // Try to find a token whose offset matches the first token.
1460b57cec5SDimitry Andric unsigned FirstCharOffset = Str.begin() - AsmString.begin();
1470b57cec5SDimitry Andric const unsigned *FirstTokOffset =
1480b57cec5SDimitry Andric llvm::lower_bound(AsmTokOffsets, FirstCharOffset);
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric // For now, assert that the start of the string exactly
1510b57cec5SDimitry Andric // corresponds to the start of a token.
1520b57cec5SDimitry Andric assert(*FirstTokOffset == FirstCharOffset);
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // Use all the original tokens for this line. (We assume the
1550b57cec5SDimitry Andric // end of the line corresponds cleanly to a token break.)
1560b57cec5SDimitry Andric unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
1570b57cec5SDimitry Andric FirstOrigToken = &AsmToks[FirstTokIndex];
1580b57cec5SDimitry Andric unsigned LastCharOffset = Str.end() - AsmString.begin();
1590b57cec5SDimitry Andric for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
1600b57cec5SDimitry Andric if (AsmTokOffsets[i] >= LastCharOffset)
1610b57cec5SDimitry Andric break;
1620b57cec5SDimitry Andric TempToks.push_back(AsmToks[i]);
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric SourceLocation
translateLocation(const llvm::SourceMgr & LSM,llvm::SMLoc SMLoc)1670b57cec5SDimitry Andric ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM,
1680b57cec5SDimitry Andric llvm::SMLoc SMLoc) {
1690b57cec5SDimitry Andric // Compute an offset into the inline asm buffer.
1700b57cec5SDimitry Andric // FIXME: This isn't right if .macro is involved (but hopefully, no
1710b57cec5SDimitry Andric // real-world code does that).
1720b57cec5SDimitry Andric const llvm::MemoryBuffer *LBuf =
1730b57cec5SDimitry Andric LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
1740b57cec5SDimitry Andric unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric // Figure out which token that offset points into.
1770b57cec5SDimitry Andric const unsigned *TokOffsetPtr = llvm::lower_bound(AsmTokOffsets, Offset);
1780b57cec5SDimitry Andric unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
1790b57cec5SDimitry Andric unsigned TokOffset = *TokOffsetPtr;
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric // If we come up with an answer which seems sane, use it; otherwise,
1820b57cec5SDimitry Andric // just point at the __asm keyword.
1830b57cec5SDimitry Andric // FIXME: Assert the answer is sane once we handle .macro correctly.
1840b57cec5SDimitry Andric SourceLocation Loc = AsmLoc;
1850b57cec5SDimitry Andric if (TokIndex < AsmToks.size()) {
1860b57cec5SDimitry Andric const Token &Tok = AsmToks[TokIndex];
1870b57cec5SDimitry Andric Loc = Tok.getLocation();
1880b57cec5SDimitry Andric Loc = Loc.getLocWithOffset(Offset - TokOffset);
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric return Loc;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
handleDiagnostic(const llvm::SMDiagnostic & D)1930b57cec5SDimitry Andric void ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) {
1940b57cec5SDimitry Andric const llvm::SourceMgr &LSM = *D.getSourceMgr();
1950b57cec5SDimitry Andric SourceLocation Loc = translateLocation(LSM, D.getLoc());
1960b57cec5SDimitry Andric TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric /// Parse an identifier in an MS-style inline assembly block.
ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> & LineToks,unsigned & NumLineToksConsumed,bool IsUnevaluatedContext)2000b57cec5SDimitry Andric ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
2010b57cec5SDimitry Andric unsigned &NumLineToksConsumed,
2020b57cec5SDimitry Andric bool IsUnevaluatedContext) {
2030b57cec5SDimitry Andric // Push a fake token on the end so that we don't overrun the token
2040b57cec5SDimitry Andric // stream. We use ';' because it expression-parsing should never
2050b57cec5SDimitry Andric // overrun it.
2060b57cec5SDimitry Andric const tok::TokenKind EndOfStream = tok::semi;
2070b57cec5SDimitry Andric Token EndOfStreamTok;
2080b57cec5SDimitry Andric EndOfStreamTok.startToken();
2090b57cec5SDimitry Andric EndOfStreamTok.setKind(EndOfStream);
2100b57cec5SDimitry Andric LineToks.push_back(EndOfStreamTok);
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric // Also copy the current token over.
2130b57cec5SDimitry Andric LineToks.push_back(Tok);
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true,
2160b57cec5SDimitry Andric /*IsReinject*/ true);
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric // Clear the current token and advance to the first token in LineToks.
2190b57cec5SDimitry Andric ConsumeAnyToken();
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric // Parse an optional scope-specifier if we're in C++.
2220b57cec5SDimitry Andric CXXScopeSpec SS;
2235ffd83dbSDimitry Andric if (getLangOpts().CPlusPlus)
2245ffd83dbSDimitry Andric ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
225*04eeddc0SDimitry Andric /*ObjectHasErrors=*/false,
2265ffd83dbSDimitry Andric /*EnteringContext=*/false);
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric // Require an identifier here.
2290b57cec5SDimitry Andric SourceLocation TemplateKWLoc;
2300b57cec5SDimitry Andric UnqualifiedId Id;
2310b57cec5SDimitry Andric bool Invalid = true;
2320b57cec5SDimitry Andric ExprResult Result;
2330b57cec5SDimitry Andric if (Tok.is(tok::kw_this)) {
2340b57cec5SDimitry Andric Result = ParseCXXThis();
2350b57cec5SDimitry Andric Invalid = false;
2360b57cec5SDimitry Andric } else {
2375ffd83dbSDimitry Andric Invalid =
2385ffd83dbSDimitry Andric ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
2395ffd83dbSDimitry Andric /*ObjectHadErrors=*/false,
2400b57cec5SDimitry Andric /*EnteringContext=*/false,
2410b57cec5SDimitry Andric /*AllowDestructorName=*/false,
2420b57cec5SDimitry Andric /*AllowConstructorName=*/false,
2435ffd83dbSDimitry Andric /*AllowDeductionGuide=*/false, &TemplateKWLoc, Id);
2440b57cec5SDimitry Andric // Perform the lookup.
2450b57cec5SDimitry Andric Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
2460b57cec5SDimitry Andric IsUnevaluatedContext);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric // While the next two tokens are 'period' 'identifier', repeatedly parse it as
2490b57cec5SDimitry Andric // a field access. We have to avoid consuming assembler directives that look
2500b57cec5SDimitry Andric // like '.' 'else'.
2510b57cec5SDimitry Andric while (Result.isUsable() && Tok.is(tok::period)) {
2520b57cec5SDimitry Andric Token IdTok = PP.LookAhead(0);
2530b57cec5SDimitry Andric if (IdTok.isNot(tok::identifier))
2540b57cec5SDimitry Andric break;
2550b57cec5SDimitry Andric ConsumeToken(); // Consume the period.
2560b57cec5SDimitry Andric IdentifierInfo *Id = Tok.getIdentifierInfo();
2570b57cec5SDimitry Andric ConsumeToken(); // Consume the identifier.
2580b57cec5SDimitry Andric Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
2590b57cec5SDimitry Andric Tok.getLocation());
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric // Figure out how many tokens we are into LineToks.
2630b57cec5SDimitry Andric unsigned LineIndex = 0;
2640b57cec5SDimitry Andric if (Tok.is(EndOfStream)) {
2650b57cec5SDimitry Andric LineIndex = LineToks.size() - 2;
2660b57cec5SDimitry Andric } else {
2670b57cec5SDimitry Andric while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
2680b57cec5SDimitry Andric LineIndex++;
2690b57cec5SDimitry Andric assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric
2730b57cec5SDimitry Andric // If we've run into the poison token we inserted before, or there
2740b57cec5SDimitry Andric // was a parsing error, then claim the entire line.
2750b57cec5SDimitry Andric if (Invalid || Tok.is(EndOfStream)) {
2760b57cec5SDimitry Andric NumLineToksConsumed = LineToks.size() - 2;
2770b57cec5SDimitry Andric } else {
2780b57cec5SDimitry Andric // Otherwise, claim up to the start of the next token.
2790b57cec5SDimitry Andric NumLineToksConsumed = LineIndex;
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric // Finally, restore the old parsing state by consuming all the tokens we
2830b57cec5SDimitry Andric // staged before, implicitly killing off the token-lexer we pushed.
2840b57cec5SDimitry Andric for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
2850b57cec5SDimitry Andric ConsumeAnyToken();
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric assert(Tok.is(EndOfStream));
2880b57cec5SDimitry Andric ConsumeToken();
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric // Leave LineToks in its original state.
2910b57cec5SDimitry Andric LineToks.pop_back();
2920b57cec5SDimitry Andric LineToks.pop_back();
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric return Result;
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric
2970b57cec5SDimitry Andric /// Turn a sequence of our tokens back into a string that we can hand
2980b57cec5SDimitry Andric /// to the MC asm parser.
buildMSAsmString(Preprocessor & PP,SourceLocation AsmLoc,ArrayRef<Token> AsmToks,SmallVectorImpl<unsigned> & TokOffsets,SmallString<512> & Asm)2990b57cec5SDimitry Andric static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,
3000b57cec5SDimitry Andric ArrayRef<Token> AsmToks,
3010b57cec5SDimitry Andric SmallVectorImpl<unsigned> &TokOffsets,
3020b57cec5SDimitry Andric SmallString<512> &Asm) {
3030b57cec5SDimitry Andric assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");
3040b57cec5SDimitry Andric
3050b57cec5SDimitry Andric // Is this the start of a new assembly statement?
3060b57cec5SDimitry Andric bool isNewStatement = true;
3070b57cec5SDimitry Andric
3080b57cec5SDimitry Andric for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
3090b57cec5SDimitry Andric const Token &Tok = AsmToks[i];
3100b57cec5SDimitry Andric
3110b57cec5SDimitry Andric // Start each new statement with a newline and a tab.
3120b57cec5SDimitry Andric if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
3130b57cec5SDimitry Andric Asm += "\n\t";
3140b57cec5SDimitry Andric isNewStatement = true;
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric
3170b57cec5SDimitry Andric // Preserve the existence of leading whitespace except at the
3180b57cec5SDimitry Andric // start of a statement.
3190b57cec5SDimitry Andric if (!isNewStatement && Tok.hasLeadingSpace())
3200b57cec5SDimitry Andric Asm += ' ';
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric // Remember the offset of this token.
3230b57cec5SDimitry Andric TokOffsets.push_back(Asm.size());
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andric // Don't actually write '__asm' into the assembly stream.
3260b57cec5SDimitry Andric if (Tok.is(tok::kw_asm)) {
3270b57cec5SDimitry Andric // Complain about __asm at the end of the stream.
3280b57cec5SDimitry Andric if (i + 1 == e) {
3290b57cec5SDimitry Andric PP.Diag(AsmLoc, diag::err_asm_empty);
3300b57cec5SDimitry Andric return true;
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric continue;
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric // Append the spelling of the token.
3370b57cec5SDimitry Andric SmallString<32> SpellingBuffer;
3380b57cec5SDimitry Andric bool SpellingInvalid = false;
3390b57cec5SDimitry Andric Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
3400b57cec5SDimitry Andric assert(!SpellingInvalid && "spelling was invalid after correct parse?");
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric // We are no longer at the start of a statement.
3430b57cec5SDimitry Andric isNewStatement = false;
3440b57cec5SDimitry Andric }
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric // Ensure that the buffer is null-terminated.
3470b57cec5SDimitry Andric Asm.push_back('\0');
3480b57cec5SDimitry Andric Asm.pop_back();
3490b57cec5SDimitry Andric
3500b57cec5SDimitry Andric assert(TokOffsets.size() == AsmToks.size());
3510b57cec5SDimitry Andric return false;
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric
3545ffd83dbSDimitry Andric // Determine if this is a GCC-style asm statement.
isGCCAsmStatement(const Token & TokAfterAsm) const3555ffd83dbSDimitry Andric bool Parser::isGCCAsmStatement(const Token &TokAfterAsm) const {
3565ffd83dbSDimitry Andric return TokAfterAsm.is(tok::l_paren) || isGNUAsmQualifier(TokAfterAsm);
3570b57cec5SDimitry Andric }
3580b57cec5SDimitry Andric
isGNUAsmQualifier(const Token & TokAfterAsm) const3595ffd83dbSDimitry Andric bool Parser::isGNUAsmQualifier(const Token &TokAfterAsm) const {
3605ffd83dbSDimitry Andric return getGNUAsmQualifier(TokAfterAsm) != GNUAsmQualifiers::AQ_unspecified;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric
3630b57cec5SDimitry Andric /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
3640b57cec5SDimitry Andric /// this routine is called to collect the tokens for an MS asm statement.
3650b57cec5SDimitry Andric ///
3660b57cec5SDimitry Andric /// [MS] ms-asm-statement:
3670b57cec5SDimitry Andric /// ms-asm-block
3680b57cec5SDimitry Andric /// ms-asm-block ms-asm-statement
3690b57cec5SDimitry Andric ///
3700b57cec5SDimitry Andric /// [MS] ms-asm-block:
3710b57cec5SDimitry Andric /// '__asm' ms-asm-line '\n'
3720b57cec5SDimitry Andric /// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
3730b57cec5SDimitry Andric ///
3740b57cec5SDimitry Andric /// [MS] ms-asm-instruction-block
3750b57cec5SDimitry Andric /// ms-asm-line
3760b57cec5SDimitry Andric /// ms-asm-line '\n' ms-asm-instruction-block
3770b57cec5SDimitry Andric ///
ParseMicrosoftAsmStatement(SourceLocation AsmLoc)3780b57cec5SDimitry Andric StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
3790b57cec5SDimitry Andric SourceManager &SrcMgr = PP.getSourceManager();
3800b57cec5SDimitry Andric SourceLocation EndLoc = AsmLoc;
3810b57cec5SDimitry Andric SmallVector<Token, 4> AsmToks;
3820b57cec5SDimitry Andric
3830b57cec5SDimitry Andric bool SingleLineMode = true;
3840b57cec5SDimitry Andric unsigned BraceNesting = 0;
3850b57cec5SDimitry Andric unsigned short savedBraceCount = BraceCount;
3860b57cec5SDimitry Andric bool InAsmComment = false;
3870b57cec5SDimitry Andric FileID FID;
3880b57cec5SDimitry Andric unsigned LineNo = 0;
3890b57cec5SDimitry Andric unsigned NumTokensRead = 0;
3900b57cec5SDimitry Andric SmallVector<SourceLocation, 4> LBraceLocs;
3910b57cec5SDimitry Andric bool SkippedStartOfLine = false;
3920b57cec5SDimitry Andric
3930b57cec5SDimitry Andric if (Tok.is(tok::l_brace)) {
3940b57cec5SDimitry Andric // Braced inline asm: consume the opening brace.
3950b57cec5SDimitry Andric SingleLineMode = false;
3960b57cec5SDimitry Andric BraceNesting = 1;
3970b57cec5SDimitry Andric EndLoc = ConsumeBrace();
3980b57cec5SDimitry Andric LBraceLocs.push_back(EndLoc);
3990b57cec5SDimitry Andric ++NumTokensRead;
4000b57cec5SDimitry Andric } else {
4010b57cec5SDimitry Andric // Single-line inline asm; compute which line it is on.
4020b57cec5SDimitry Andric std::pair<FileID, unsigned> ExpAsmLoc =
4030b57cec5SDimitry Andric SrcMgr.getDecomposedExpansionLoc(EndLoc);
4040b57cec5SDimitry Andric FID = ExpAsmLoc.first;
4050b57cec5SDimitry Andric LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
4060b57cec5SDimitry Andric LBraceLocs.push_back(SourceLocation());
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric
4090b57cec5SDimitry Andric SourceLocation TokLoc = Tok.getLocation();
4100b57cec5SDimitry Andric do {
4110b57cec5SDimitry Andric // If we hit EOF, we're done, period.
4120b57cec5SDimitry Andric if (isEofOrEom())
4130b57cec5SDimitry Andric break;
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric if (!InAsmComment && Tok.is(tok::l_brace)) {
4160b57cec5SDimitry Andric // Consume the opening brace.
4170b57cec5SDimitry Andric SkippedStartOfLine = Tok.isAtStartOfLine();
4180b57cec5SDimitry Andric AsmToks.push_back(Tok);
4190b57cec5SDimitry Andric EndLoc = ConsumeBrace();
4200b57cec5SDimitry Andric BraceNesting++;
4210b57cec5SDimitry Andric LBraceLocs.push_back(EndLoc);
4220b57cec5SDimitry Andric TokLoc = Tok.getLocation();
4230b57cec5SDimitry Andric ++NumTokensRead;
4240b57cec5SDimitry Andric continue;
4250b57cec5SDimitry Andric } else if (!InAsmComment && Tok.is(tok::semi)) {
4260b57cec5SDimitry Andric // A semicolon in an asm is the start of a comment.
4270b57cec5SDimitry Andric InAsmComment = true;
4280b57cec5SDimitry Andric if (!SingleLineMode) {
4290b57cec5SDimitry Andric // Compute which line the comment is on.
4300b57cec5SDimitry Andric std::pair<FileID, unsigned> ExpSemiLoc =
4310b57cec5SDimitry Andric SrcMgr.getDecomposedExpansionLoc(TokLoc);
4320b57cec5SDimitry Andric FID = ExpSemiLoc.first;
4330b57cec5SDimitry Andric LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric } else if (SingleLineMode || InAsmComment) {
4360b57cec5SDimitry Andric // If end-of-line is significant, check whether this token is on a
4370b57cec5SDimitry Andric // new line.
4380b57cec5SDimitry Andric std::pair<FileID, unsigned> ExpLoc =
4390b57cec5SDimitry Andric SrcMgr.getDecomposedExpansionLoc(TokLoc);
4400b57cec5SDimitry Andric if (ExpLoc.first != FID ||
4410b57cec5SDimitry Andric SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
4420b57cec5SDimitry Andric // If this is a single-line __asm, we're done, except if the next
4430b57cec5SDimitry Andric // line is MS-style asm too, in which case we finish a comment
4440b57cec5SDimitry Andric // if needed and then keep processing the next line as a single
4450b57cec5SDimitry Andric // line __asm.
4460b57cec5SDimitry Andric bool isAsm = Tok.is(tok::kw_asm);
4470b57cec5SDimitry Andric if (SingleLineMode && (!isAsm || isGCCAsmStatement(NextToken())))
4480b57cec5SDimitry Andric break;
4490b57cec5SDimitry Andric // We're no longer in a comment.
4500b57cec5SDimitry Andric InAsmComment = false;
4510b57cec5SDimitry Andric if (isAsm) {
4520b57cec5SDimitry Andric // If this is a new __asm {} block we want to process it separately
4530b57cec5SDimitry Andric // from the single-line __asm statements
4540b57cec5SDimitry Andric if (PP.LookAhead(0).is(tok::l_brace))
4550b57cec5SDimitry Andric break;
4560b57cec5SDimitry Andric LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second);
4570b57cec5SDimitry Andric SkippedStartOfLine = Tok.isAtStartOfLine();
4580b57cec5SDimitry Andric } else if (Tok.is(tok::semi)) {
4590b57cec5SDimitry Andric // A multi-line asm-statement, where next line is a comment
4600b57cec5SDimitry Andric InAsmComment = true;
4610b57cec5SDimitry Andric FID = ExpLoc.first;
4620b57cec5SDimitry Andric LineNo = SrcMgr.getLineNumber(FID, ExpLoc.second);
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric } else if (!InAsmComment && Tok.is(tok::r_brace)) {
4650b57cec5SDimitry Andric // In MSVC mode, braces only participate in brace matching and
4660b57cec5SDimitry Andric // separating the asm statements. This is an intentional
4670b57cec5SDimitry Andric // departure from the Apple gcc behavior.
4680b57cec5SDimitry Andric if (!BraceNesting)
4690b57cec5SDimitry Andric break;
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric }
4720b57cec5SDimitry Andric if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
4730b57cec5SDimitry Andric BraceCount == (savedBraceCount + BraceNesting)) {
4740b57cec5SDimitry Andric // Consume the closing brace.
4750b57cec5SDimitry Andric SkippedStartOfLine = Tok.isAtStartOfLine();
4760b57cec5SDimitry Andric // Don't want to add the closing brace of the whole asm block
4770b57cec5SDimitry Andric if (SingleLineMode || BraceNesting > 1) {
4780b57cec5SDimitry Andric Tok.clearFlag(Token::LeadingSpace);
4790b57cec5SDimitry Andric AsmToks.push_back(Tok);
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric EndLoc = ConsumeBrace();
4820b57cec5SDimitry Andric BraceNesting--;
4830b57cec5SDimitry Andric // Finish if all of the opened braces in the inline asm section were
4840b57cec5SDimitry Andric // consumed.
4850b57cec5SDimitry Andric if (BraceNesting == 0 && !SingleLineMode)
4860b57cec5SDimitry Andric break;
4870b57cec5SDimitry Andric else {
4880b57cec5SDimitry Andric LBraceLocs.pop_back();
4890b57cec5SDimitry Andric TokLoc = Tok.getLocation();
4900b57cec5SDimitry Andric ++NumTokensRead;
4910b57cec5SDimitry Andric continue;
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric
4950b57cec5SDimitry Andric // Consume the next token; make sure we don't modify the brace count etc.
4960b57cec5SDimitry Andric // if we are in a comment.
4970b57cec5SDimitry Andric EndLoc = TokLoc;
4980b57cec5SDimitry Andric if (InAsmComment)
4990b57cec5SDimitry Andric PP.Lex(Tok);
5000b57cec5SDimitry Andric else {
5010b57cec5SDimitry Andric // Set the token as the start of line if we skipped the original start
5020b57cec5SDimitry Andric // of line token in case it was a nested brace.
5030b57cec5SDimitry Andric if (SkippedStartOfLine)
5040b57cec5SDimitry Andric Tok.setFlag(Token::StartOfLine);
5050b57cec5SDimitry Andric AsmToks.push_back(Tok);
5060b57cec5SDimitry Andric ConsumeAnyToken();
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric TokLoc = Tok.getLocation();
5090b57cec5SDimitry Andric ++NumTokensRead;
5100b57cec5SDimitry Andric SkippedStartOfLine = false;
511*04eeddc0SDimitry Andric } while (true);
5120b57cec5SDimitry Andric
5130b57cec5SDimitry Andric if (BraceNesting && BraceCount != savedBraceCount) {
5140b57cec5SDimitry Andric // __asm without closing brace (this can happen at EOF).
5150b57cec5SDimitry Andric for (unsigned i = 0; i < BraceNesting; ++i) {
5160b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::r_brace;
5170b57cec5SDimitry Andric Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
5180b57cec5SDimitry Andric LBraceLocs.pop_back();
5190b57cec5SDimitry Andric }
5200b57cec5SDimitry Andric return StmtError();
5210b57cec5SDimitry Andric } else if (NumTokensRead == 0) {
5220b57cec5SDimitry Andric // Empty __asm.
5230b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::l_brace;
5240b57cec5SDimitry Andric return StmtError();
5250b57cec5SDimitry Andric }
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric // Okay, prepare to use MC to parse the assembly.
5280b57cec5SDimitry Andric SmallVector<StringRef, 4> ConstraintRefs;
5290b57cec5SDimitry Andric SmallVector<Expr *, 4> Exprs;
5300b57cec5SDimitry Andric SmallVector<StringRef, 4> ClobberRefs;
5310b57cec5SDimitry Andric
5320b57cec5SDimitry Andric // We need an actual supported target.
5330b57cec5SDimitry Andric const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
5340b57cec5SDimitry Andric const std::string &TT = TheTriple.getTriple();
5350b57cec5SDimitry Andric const llvm::Target *TheTarget = nullptr;
536480093f4SDimitry Andric if (!TheTriple.isX86()) {
5370b57cec5SDimitry Andric Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
5380b57cec5SDimitry Andric } else {
5390b57cec5SDimitry Andric std::string Error;
5400b57cec5SDimitry Andric TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
5410b57cec5SDimitry Andric if (!TheTarget)
5420b57cec5SDimitry Andric Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric
5450b57cec5SDimitry Andric assert(!LBraceLocs.empty() && "Should have at least one location here");
5460b57cec5SDimitry Andric
547480093f4SDimitry Andric SmallString<512> AsmString;
548480093f4SDimitry Andric auto EmptyStmt = [&] {
549480093f4SDimitry Andric return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmString,
550480093f4SDimitry Andric /*NumOutputs*/ 0, /*NumInputs*/ 0,
551480093f4SDimitry Andric ConstraintRefs, ClobberRefs, Exprs, EndLoc);
552480093f4SDimitry Andric };
5530b57cec5SDimitry Andric // If we don't support assembly, or the assembly is empty, we don't
5540b57cec5SDimitry Andric // need to instantiate the AsmParser, etc.
5550b57cec5SDimitry Andric if (!TheTarget || AsmToks.empty()) {
556480093f4SDimitry Andric return EmptyStmt();
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric
5590b57cec5SDimitry Andric // Expand the tokens into a string buffer.
5600b57cec5SDimitry Andric SmallVector<unsigned, 8> TokOffsets;
5610b57cec5SDimitry Andric if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
5620b57cec5SDimitry Andric return StmtError();
5630b57cec5SDimitry Andric
5640b57cec5SDimitry Andric const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts();
5650b57cec5SDimitry Andric std::string FeaturesStr =
5660b57cec5SDimitry Andric llvm::join(TO.Features.begin(), TO.Features.end(), ",");
5670b57cec5SDimitry Andric
5680b57cec5SDimitry Andric std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
569480093f4SDimitry Andric if (!MRI) {
570480093f4SDimitry Andric Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
571480093f4SDimitry Andric << "target MC unavailable";
572480093f4SDimitry Andric return EmptyStmt();
573480093f4SDimitry Andric }
574480093f4SDimitry Andric // FIXME: init MCOptions from sanitizer flags here.
575480093f4SDimitry Andric llvm::MCTargetOptions MCOptions;
576480093f4SDimitry Andric std::unique_ptr<llvm::MCAsmInfo> MAI(
577480093f4SDimitry Andric TheTarget->createMCAsmInfo(*MRI, TT, MCOptions));
5780b57cec5SDimitry Andric // Get the instruction descriptor.
5790b57cec5SDimitry Andric std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
5800b57cec5SDimitry Andric std::unique_ptr<llvm::MCSubtargetInfo> STI(
5810b57cec5SDimitry Andric TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr));
582480093f4SDimitry Andric // Target MCTargetDesc may not be linked in clang-based tools.
583fe6060f1SDimitry Andric
584fe6060f1SDimitry Andric if (!MAI || !MII || !STI) {
585480093f4SDimitry Andric Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
586480093f4SDimitry Andric << "target MC unavailable";
587480093f4SDimitry Andric return EmptyStmt();
588480093f4SDimitry Andric }
5890b57cec5SDimitry Andric
5900b57cec5SDimitry Andric llvm::SourceMgr TempSrcMgr;
591fe6060f1SDimitry Andric llvm::MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &TempSrcMgr);
592fe6060f1SDimitry Andric std::unique_ptr<llvm::MCObjectFileInfo> MOFI(
593fe6060f1SDimitry Andric TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
594fe6060f1SDimitry Andric Ctx.setObjectFileInfo(MOFI.get());
595fe6060f1SDimitry Andric
5960b57cec5SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer =
5970b57cec5SDimitry Andric llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric // Tell SrcMgr about this buffer, which is what the parser will pick up.
6000b57cec5SDimitry Andric TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
6030b57cec5SDimitry Andric std::unique_ptr<llvm::MCAsmParser> Parser(
6040b57cec5SDimitry Andric createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
6050b57cec5SDimitry Andric
6060b57cec5SDimitry Andric std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
6070b57cec5SDimitry Andric TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
608480093f4SDimitry Andric // Target AsmParser may not be linked in clang-based tools.
609480093f4SDimitry Andric if (!TargetParser) {
610480093f4SDimitry Andric Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
611480093f4SDimitry Andric << "target ASM parser unavailable";
612480093f4SDimitry Andric return EmptyStmt();
613480093f4SDimitry Andric }
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric std::unique_ptr<llvm::MCInstPrinter> IP(
6160b57cec5SDimitry Andric TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
6170b57cec5SDimitry Andric
6180b57cec5SDimitry Andric // Change to the Intel dialect.
6190b57cec5SDimitry Andric Parser->setAssemblerDialect(1);
6200b57cec5SDimitry Andric Parser->setTargetParser(*TargetParser.get());
6215ffd83dbSDimitry Andric Parser->setParsingMSInlineAsm(true);
6225ffd83dbSDimitry Andric TargetParser->setParsingMSInlineAsm(true);
6230b57cec5SDimitry Andric
6240b57cec5SDimitry Andric ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,
6250b57cec5SDimitry Andric TokOffsets);
6260b57cec5SDimitry Andric TargetParser->setSemaCallback(&Callback);
6270b57cec5SDimitry Andric TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
6280b57cec5SDimitry Andric &Callback);
6290b57cec5SDimitry Andric
6300b57cec5SDimitry Andric unsigned NumOutputs;
6310b57cec5SDimitry Andric unsigned NumInputs;
6320b57cec5SDimitry Andric std::string AsmStringIR;
6330b57cec5SDimitry Andric SmallVector<std::pair<void *, bool>, 4> OpExprs;
6340b57cec5SDimitry Andric SmallVector<std::string, 4> Constraints;
6350b57cec5SDimitry Andric SmallVector<std::string, 4> Clobbers;
636fe6060f1SDimitry Andric if (Parser->parseMSInlineAsm(AsmStringIR, NumOutputs, NumInputs, OpExprs,
637fe6060f1SDimitry Andric Constraints, Clobbers, MII.get(), IP.get(),
638fe6060f1SDimitry Andric Callback))
6390b57cec5SDimitry Andric return StmtError();
6400b57cec5SDimitry Andric
6410b57cec5SDimitry Andric // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber
6420b57cec5SDimitry Andric // constraints. Clang always adds fpsr to the clobber list anyway.
6430b57cec5SDimitry Andric llvm::erase_if(Clobbers, [](const std::string &C) {
6440b57cec5SDimitry Andric return C == "fpsr" || C == "mxcsr";
6450b57cec5SDimitry Andric });
6460b57cec5SDimitry Andric
6470b57cec5SDimitry Andric // Build the vector of clobber StringRefs.
6480b57cec5SDimitry Andric ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
6490b57cec5SDimitry Andric
6500b57cec5SDimitry Andric // Recast the void pointers and build the vector of constraint StringRefs.
6510b57cec5SDimitry Andric unsigned NumExprs = NumOutputs + NumInputs;
6520b57cec5SDimitry Andric ConstraintRefs.resize(NumExprs);
6530b57cec5SDimitry Andric Exprs.resize(NumExprs);
6540b57cec5SDimitry Andric for (unsigned i = 0, e = NumExprs; i != e; ++i) {
6550b57cec5SDimitry Andric Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
6560b57cec5SDimitry Andric if (!OpExpr)
6570b57cec5SDimitry Andric return StmtError();
6580b57cec5SDimitry Andric
6590b57cec5SDimitry Andric // Need address of variable.
6600b57cec5SDimitry Andric if (OpExprs[i].second)
6610b57cec5SDimitry Andric OpExpr =
6620b57cec5SDimitry Andric Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
6630b57cec5SDimitry Andric
6640b57cec5SDimitry Andric ConstraintRefs[i] = StringRef(Constraints[i]);
6650b57cec5SDimitry Andric Exprs[i] = OpExpr;
6660b57cec5SDimitry Andric }
6670b57cec5SDimitry Andric
6680b57cec5SDimitry Andric // FIXME: We should be passing source locations for better diagnostics.
6690b57cec5SDimitry Andric return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
6700b57cec5SDimitry Andric NumOutputs, NumInputs, ConstraintRefs,
6710b57cec5SDimitry Andric ClobberRefs, Exprs, EndLoc);
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric
6745ffd83dbSDimitry Andric /// parseGNUAsmQualifierListOpt - Parse a GNU extended asm qualifier list.
6755ffd83dbSDimitry Andric /// asm-qualifier:
6765ffd83dbSDimitry Andric /// volatile
6775ffd83dbSDimitry Andric /// inline
6785ffd83dbSDimitry Andric /// goto
6795ffd83dbSDimitry Andric ///
6805ffd83dbSDimitry Andric /// asm-qualifier-list:
6815ffd83dbSDimitry Andric /// asm-qualifier
6825ffd83dbSDimitry Andric /// asm-qualifier-list asm-qualifier
parseGNUAsmQualifierListOpt(GNUAsmQualifiers & AQ)6835ffd83dbSDimitry Andric bool Parser::parseGNUAsmQualifierListOpt(GNUAsmQualifiers &AQ) {
684*04eeddc0SDimitry Andric while (true) {
6855ffd83dbSDimitry Andric const GNUAsmQualifiers::AQ A = getGNUAsmQualifier(Tok);
6865ffd83dbSDimitry Andric if (A == GNUAsmQualifiers::AQ_unspecified) {
6875ffd83dbSDimitry Andric if (Tok.isNot(tok::l_paren)) {
6885ffd83dbSDimitry Andric Diag(Tok.getLocation(), diag::err_asm_qualifier_ignored);
6895ffd83dbSDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
6905ffd83dbSDimitry Andric return true;
6915ffd83dbSDimitry Andric }
6925ffd83dbSDimitry Andric return false;
6935ffd83dbSDimitry Andric }
6945ffd83dbSDimitry Andric if (AQ.setAsmQualifier(A))
6955ffd83dbSDimitry Andric Diag(Tok.getLocation(), diag::err_asm_duplicate_qual)
6965ffd83dbSDimitry Andric << GNUAsmQualifiers::getQualifierName(A);
6975ffd83dbSDimitry Andric ConsumeToken();
6985ffd83dbSDimitry Andric }
6995ffd83dbSDimitry Andric return false;
7005ffd83dbSDimitry Andric }
7015ffd83dbSDimitry Andric
7020b57cec5SDimitry Andric /// ParseAsmStatement - Parse a GNU extended asm statement.
7030b57cec5SDimitry Andric /// asm-statement:
7040b57cec5SDimitry Andric /// gnu-asm-statement
7050b57cec5SDimitry Andric /// ms-asm-statement
7060b57cec5SDimitry Andric ///
7070b57cec5SDimitry Andric /// [GNU] gnu-asm-statement:
7085ffd83dbSDimitry Andric /// 'asm' asm-qualifier-list[opt] '(' asm-argument ')' ';'
7090b57cec5SDimitry Andric ///
7100b57cec5SDimitry Andric /// [GNU] asm-argument:
7110b57cec5SDimitry Andric /// asm-string-literal
7120b57cec5SDimitry Andric /// asm-string-literal ':' asm-operands[opt]
7130b57cec5SDimitry Andric /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
7140b57cec5SDimitry Andric /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
7150b57cec5SDimitry Andric /// ':' asm-clobbers
7160b57cec5SDimitry Andric ///
7170b57cec5SDimitry Andric /// [GNU] asm-clobbers:
7180b57cec5SDimitry Andric /// asm-string-literal
7190b57cec5SDimitry Andric /// asm-clobbers ',' asm-string-literal
7200b57cec5SDimitry Andric ///
ParseAsmStatement(bool & msAsm)7210b57cec5SDimitry Andric StmtResult Parser::ParseAsmStatement(bool &msAsm) {
7220b57cec5SDimitry Andric assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
7230b57cec5SDimitry Andric SourceLocation AsmLoc = ConsumeToken();
7240b57cec5SDimitry Andric
7250b57cec5SDimitry Andric if (getLangOpts().AsmBlocks && !isGCCAsmStatement(Tok)) {
7260b57cec5SDimitry Andric msAsm = true;
7270b57cec5SDimitry Andric return ParseMicrosoftAsmStatement(AsmLoc);
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric
7300b57cec5SDimitry Andric SourceLocation Loc = Tok.getLocation();
7315ffd83dbSDimitry Andric GNUAsmQualifiers GAQ;
7325ffd83dbSDimitry Andric if (parseGNUAsmQualifierListOpt(GAQ))
7330b57cec5SDimitry Andric return StmtError();
7345ffd83dbSDimitry Andric
7355ffd83dbSDimitry Andric if (GAQ.isGoto() && getLangOpts().SpeculativeLoadHardening)
7365ffd83dbSDimitry Andric Diag(Loc, diag::warn_slh_does_not_support_asm_goto);
7375ffd83dbSDimitry Andric
7380b57cec5SDimitry Andric BalancedDelimiterTracker T(*this, tok::l_paren);
7390b57cec5SDimitry Andric T.consumeOpen();
7400b57cec5SDimitry Andric
741480093f4SDimitry Andric ExprResult AsmString(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
7420b57cec5SDimitry Andric
7430b57cec5SDimitry Andric // Check if GNU-style InlineAsm is disabled.
7440b57cec5SDimitry Andric // Error on anything other than empty string.
7450b57cec5SDimitry Andric if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) {
7460b57cec5SDimitry Andric const auto *SL = cast<StringLiteral>(AsmString.get());
7470b57cec5SDimitry Andric if (!SL->getString().trim().empty())
7480b57cec5SDimitry Andric Diag(Loc, diag::err_gnu_inline_asm_disabled);
7490b57cec5SDimitry Andric }
7500b57cec5SDimitry Andric
7510b57cec5SDimitry Andric if (AsmString.isInvalid()) {
7520b57cec5SDimitry Andric // Consume up to and including the closing paren.
7530b57cec5SDimitry Andric T.skipToEnd();
7540b57cec5SDimitry Andric return StmtError();
7550b57cec5SDimitry Andric }
7560b57cec5SDimitry Andric
7570b57cec5SDimitry Andric SmallVector<IdentifierInfo *, 4> Names;
7580b57cec5SDimitry Andric ExprVector Constraints;
7590b57cec5SDimitry Andric ExprVector Exprs;
7600b57cec5SDimitry Andric ExprVector Clobbers;
7610b57cec5SDimitry Andric
7620b57cec5SDimitry Andric if (Tok.is(tok::r_paren)) {
7630b57cec5SDimitry Andric // We have a simple asm expression like 'asm("foo")'.
7640b57cec5SDimitry Andric T.consumeClose();
7655ffd83dbSDimitry Andric return Actions.ActOnGCCAsmStmt(
7665ffd83dbSDimitry Andric AsmLoc, /*isSimple*/ true, GAQ.isVolatile(),
7675ffd83dbSDimitry Andric /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, Constraints, Exprs,
7685ffd83dbSDimitry Andric AsmString.get(), Clobbers, /*NumLabels*/ 0, T.getCloseLocation());
7690b57cec5SDimitry Andric }
7700b57cec5SDimitry Andric
7710b57cec5SDimitry Andric // Parse Outputs, if present.
7720b57cec5SDimitry Andric bool AteExtraColon = false;
7730b57cec5SDimitry Andric if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
7740b57cec5SDimitry Andric // In C++ mode, parse "::" like ": :".
7750b57cec5SDimitry Andric AteExtraColon = Tok.is(tok::coloncolon);
7760b57cec5SDimitry Andric ConsumeToken();
7770b57cec5SDimitry Andric
7780b57cec5SDimitry Andric if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
7790b57cec5SDimitry Andric return StmtError();
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric
7820b57cec5SDimitry Andric unsigned NumOutputs = Names.size();
7830b57cec5SDimitry Andric
7840b57cec5SDimitry Andric // Parse Inputs, if present.
7850b57cec5SDimitry Andric if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
7860b57cec5SDimitry Andric // In C++ mode, parse "::" like ": :".
7870b57cec5SDimitry Andric if (AteExtraColon)
7880b57cec5SDimitry Andric AteExtraColon = false;
7890b57cec5SDimitry Andric else {
7900b57cec5SDimitry Andric AteExtraColon = Tok.is(tok::coloncolon);
7910b57cec5SDimitry Andric ConsumeToken();
7920b57cec5SDimitry Andric }
7930b57cec5SDimitry Andric
7940b57cec5SDimitry Andric if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
7950b57cec5SDimitry Andric return StmtError();
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric
7980b57cec5SDimitry Andric assert(Names.size() == Constraints.size() &&
7990b57cec5SDimitry Andric Constraints.size() == Exprs.size() && "Input operand size mismatch!");
8000b57cec5SDimitry Andric
8010b57cec5SDimitry Andric unsigned NumInputs = Names.size() - NumOutputs;
8020b57cec5SDimitry Andric
8030b57cec5SDimitry Andric // Parse the clobbers, if present.
8040b57cec5SDimitry Andric if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
8050b57cec5SDimitry Andric if (AteExtraColon)
8060b57cec5SDimitry Andric AteExtraColon = false;
8070b57cec5SDimitry Andric else {
8080b57cec5SDimitry Andric AteExtraColon = Tok.is(tok::coloncolon);
8090b57cec5SDimitry Andric ConsumeToken();
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric // Parse the asm-string list for clobbers if present.
8120b57cec5SDimitry Andric if (!AteExtraColon && isTokenStringLiteral()) {
813*04eeddc0SDimitry Andric while (true) {
814480093f4SDimitry Andric ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
8150b57cec5SDimitry Andric
8160b57cec5SDimitry Andric if (Clobber.isInvalid())
8170b57cec5SDimitry Andric break;
8180b57cec5SDimitry Andric
8190b57cec5SDimitry Andric Clobbers.push_back(Clobber.get());
8200b57cec5SDimitry Andric
8210b57cec5SDimitry Andric if (!TryConsumeToken(tok::comma))
8220b57cec5SDimitry Andric break;
8230b57cec5SDimitry Andric }
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric }
8265ffd83dbSDimitry Andric if (!GAQ.isGoto() && (Tok.isNot(tok::r_paren) || AteExtraColon)) {
8270b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::r_paren;
8280b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
8290b57cec5SDimitry Andric return StmtError();
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric
8320b57cec5SDimitry Andric // Parse the goto label, if present.
8330b57cec5SDimitry Andric unsigned NumLabels = 0;
8340b57cec5SDimitry Andric if (AteExtraColon || Tok.is(tok::colon)) {
8350b57cec5SDimitry Andric if (!AteExtraColon)
8360b57cec5SDimitry Andric ConsumeToken();
8370b57cec5SDimitry Andric
8380b57cec5SDimitry Andric while (true) {
8390b57cec5SDimitry Andric if (Tok.isNot(tok::identifier)) {
8400b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::identifier;
8410b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
8420b57cec5SDimitry Andric return StmtError();
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
8450b57cec5SDimitry Andric Tok.getLocation());
8460b57cec5SDimitry Andric Names.push_back(Tok.getIdentifierInfo());
8470b57cec5SDimitry Andric if (!LD) {
8480b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
8490b57cec5SDimitry Andric return StmtError();
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric ExprResult Res =
8520b57cec5SDimitry Andric Actions.ActOnAddrLabel(Tok.getLocation(), Tok.getLocation(), LD);
8530b57cec5SDimitry Andric Exprs.push_back(Res.get());
8540b57cec5SDimitry Andric NumLabels++;
8550b57cec5SDimitry Andric ConsumeToken();
8560b57cec5SDimitry Andric if (!TryConsumeToken(tok::comma))
8570b57cec5SDimitry Andric break;
8580b57cec5SDimitry Andric }
8595ffd83dbSDimitry Andric } else if (GAQ.isGoto()) {
8600b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::colon;
8610b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
8620b57cec5SDimitry Andric return StmtError();
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric T.consumeClose();
8655ffd83dbSDimitry Andric return Actions.ActOnGCCAsmStmt(AsmLoc, false, GAQ.isVolatile(), NumOutputs,
8665ffd83dbSDimitry Andric NumInputs, Names.data(), Constraints, Exprs,
8675ffd83dbSDimitry Andric AsmString.get(), Clobbers, NumLabels,
8680b57cec5SDimitry Andric T.getCloseLocation());
8690b57cec5SDimitry Andric }
8700b57cec5SDimitry Andric
8710b57cec5SDimitry Andric /// ParseAsmOperands - Parse the asm-operands production as used by
8720b57cec5SDimitry Andric /// asm-statement, assuming the leading ':' token was eaten.
8730b57cec5SDimitry Andric ///
8740b57cec5SDimitry Andric /// [GNU] asm-operands:
8750b57cec5SDimitry Andric /// asm-operand
8760b57cec5SDimitry Andric /// asm-operands ',' asm-operand
8770b57cec5SDimitry Andric ///
8780b57cec5SDimitry Andric /// [GNU] asm-operand:
8790b57cec5SDimitry Andric /// asm-string-literal '(' expression ')'
8800b57cec5SDimitry Andric /// '[' identifier ']' asm-string-literal '(' expression ')'
8810b57cec5SDimitry Andric ///
8820b57cec5SDimitry Andric //
8830b57cec5SDimitry Andric // FIXME: Avoid unnecessary std::string trashing.
ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo * > & Names,SmallVectorImpl<Expr * > & Constraints,SmallVectorImpl<Expr * > & Exprs)8840b57cec5SDimitry Andric bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
8850b57cec5SDimitry Andric SmallVectorImpl<Expr *> &Constraints,
8860b57cec5SDimitry Andric SmallVectorImpl<Expr *> &Exprs) {
8870b57cec5SDimitry Andric // 'asm-operands' isn't present?
8880b57cec5SDimitry Andric if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
8890b57cec5SDimitry Andric return false;
8900b57cec5SDimitry Andric
891*04eeddc0SDimitry Andric while (true) {
8920b57cec5SDimitry Andric // Read the [id] if present.
8930b57cec5SDimitry Andric if (Tok.is(tok::l_square)) {
8940b57cec5SDimitry Andric BalancedDelimiterTracker T(*this, tok::l_square);
8950b57cec5SDimitry Andric T.consumeOpen();
8960b57cec5SDimitry Andric
8970b57cec5SDimitry Andric if (Tok.isNot(tok::identifier)) {
8980b57cec5SDimitry Andric Diag(Tok, diag::err_expected) << tok::identifier;
8990b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
9000b57cec5SDimitry Andric return true;
9010b57cec5SDimitry Andric }
9020b57cec5SDimitry Andric
9030b57cec5SDimitry Andric IdentifierInfo *II = Tok.getIdentifierInfo();
9040b57cec5SDimitry Andric ConsumeToken();
9050b57cec5SDimitry Andric
9060b57cec5SDimitry Andric Names.push_back(II);
9070b57cec5SDimitry Andric T.consumeClose();
9080b57cec5SDimitry Andric } else
9090b57cec5SDimitry Andric Names.push_back(nullptr);
9100b57cec5SDimitry Andric
911480093f4SDimitry Andric ExprResult Constraint(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
9120b57cec5SDimitry Andric if (Constraint.isInvalid()) {
9130b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
9140b57cec5SDimitry Andric return true;
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric Constraints.push_back(Constraint.get());
9170b57cec5SDimitry Andric
9180b57cec5SDimitry Andric if (Tok.isNot(tok::l_paren)) {
9190b57cec5SDimitry Andric Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
9200b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
9210b57cec5SDimitry Andric return true;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric
9240b57cec5SDimitry Andric // Read the parenthesized expression.
9250b57cec5SDimitry Andric BalancedDelimiterTracker T(*this, tok::l_paren);
9260b57cec5SDimitry Andric T.consumeOpen();
9270b57cec5SDimitry Andric ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
9280b57cec5SDimitry Andric T.consumeClose();
9290b57cec5SDimitry Andric if (Res.isInvalid()) {
9300b57cec5SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi);
9310b57cec5SDimitry Andric return true;
9320b57cec5SDimitry Andric }
9330b57cec5SDimitry Andric Exprs.push_back(Res.get());
9340b57cec5SDimitry Andric // Eat the comma and continue parsing if it exists.
9350b57cec5SDimitry Andric if (!TryConsumeToken(tok::comma))
9360b57cec5SDimitry Andric return false;
9370b57cec5SDimitry Andric }
9380b57cec5SDimitry Andric }
9395ffd83dbSDimitry Andric
getQualifierName(AQ Qualifier)9405ffd83dbSDimitry Andric const char *Parser::GNUAsmQualifiers::getQualifierName(AQ Qualifier) {
9415ffd83dbSDimitry Andric switch (Qualifier) {
9425ffd83dbSDimitry Andric case AQ_volatile: return "volatile";
9435ffd83dbSDimitry Andric case AQ_inline: return "inline";
9445ffd83dbSDimitry Andric case AQ_goto: return "goto";
9455ffd83dbSDimitry Andric case AQ_unspecified: return "unspecified";
9465ffd83dbSDimitry Andric }
9475ffd83dbSDimitry Andric llvm_unreachable("Unknown GNUAsmQualifier");
9485ffd83dbSDimitry Andric }
9495ffd83dbSDimitry Andric
9505ffd83dbSDimitry Andric Parser::GNUAsmQualifiers::AQ
getGNUAsmQualifier(const Token & Tok) const9515ffd83dbSDimitry Andric Parser::getGNUAsmQualifier(const Token &Tok) const {
9525ffd83dbSDimitry Andric switch (Tok.getKind()) {
9535ffd83dbSDimitry Andric case tok::kw_volatile: return GNUAsmQualifiers::AQ_volatile;
9545ffd83dbSDimitry Andric case tok::kw_inline: return GNUAsmQualifiers::AQ_inline;
9555ffd83dbSDimitry Andric case tok::kw_goto: return GNUAsmQualifiers::AQ_goto;
9565ffd83dbSDimitry Andric default: return GNUAsmQualifiers::AQ_unspecified;
9575ffd83dbSDimitry Andric }
9585ffd83dbSDimitry Andric }
setAsmQualifier(AQ Qualifier)9595ffd83dbSDimitry Andric bool Parser::GNUAsmQualifiers::setAsmQualifier(AQ Qualifier) {
9605ffd83dbSDimitry Andric bool IsDuplicate = Qualifiers & Qualifier;
9615ffd83dbSDimitry Andric Qualifiers |= Qualifier;
9625ffd83dbSDimitry Andric return IsDuplicate;
9635ffd83dbSDimitry Andric }
964