19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/MC/MCAsmInfo.h" 22 #include "llvm/MC/MCContext.h" 23 #include "llvm/MC/MCInstPrinter.h" 24 #include "llvm/MC/MCInstrInfo.h" 25 #include "llvm/MC/MCObjectFileInfo.h" 26 #include "llvm/MC/MCParser/MCAsmParser.h" 27 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 28 #include "llvm/MC/MCRegisterInfo.h" 29 #include "llvm/MC/MCStreamer.h" 30 #include "llvm/MC/MCSubtargetInfo.h" 31 #include "llvm/MC/MCTargetOptions.h" 32 #include "llvm/Support/SourceMgr.h" 33 #include "llvm/Support/TargetRegistry.h" 34 #include "llvm/Support/TargetSelect.h" 35 using namespace clang;
38 class ClangAsmParserCallback :
public llvm::MCAsmParserSemaCallback {
52 : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
53 AsmTokOffsets(Offsets) {
54 assert(AsmToks.size() == AsmTokOffsets.size());
57 void LookupInlineAsmIdentifier(StringRef &LineBuf,
58 llvm::InlineAsmIdentifierInfo &Info,
59 bool IsUnevaluatedContext)
override;
61 StringRef LookupInlineAsmLabel(StringRef
Identifier, llvm::SourceMgr &LSM,
65 bool LookupInlineAsmField(StringRef
Base, StringRef Member,
66 unsigned &
Offset)
override {
71 static void DiagHandlerCallback(
const llvm::SMDiagnostic &D,
void *Context) {
72 ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
78 const Token *&FirstOrigToken)
const;
83 void handleDiagnostic(
const llvm::SMDiagnostic &D);
87 void ClangAsmParserCallback::LookupInlineAsmIdentifier(
88 StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info,
89 bool IsUnevaluatedContext) {
92 const Token *FirstOrigToken =
nullptr;
93 findTokensForString(LineBuf, LineToks, FirstOrigToken);
95 unsigned NumConsumedToks;
97 IsUnevaluatedContext);
101 if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
106 assert(FirstOrigToken &&
"not using original tokens?");
109 assert(FirstOrigToken[NumConsumedToks].getLocation() ==
110 LineToks[NumConsumedToks].getLocation());
111 unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
112 unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
116 unsigned TotalOffset =
117 (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
118 AsmTokOffsets[FirstIndex]);
119 LineBuf = LineBuf.substr(0, TotalOffset);
128 StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef
Identifier,
129 llvm::SourceMgr &LSM,
130 llvm::SMLoc Location,
138 void ClangAsmParserCallback::findTokensForString(
140 const Token *&FirstOrigToken)
const {
143 assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
144 !std::less<const char *>()(AsmString.end(), Str.end()));
147 unsigned FirstCharOffset = Str.begin() - AsmString.begin();
148 const unsigned *FirstTokOffset = std::lower_bound(
149 AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
153 assert(*FirstTokOffset == FirstCharOffset);
157 unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
158 FirstOrigToken = &AsmToks[FirstTokIndex];
159 unsigned LastCharOffset = Str.end() - AsmString.begin();
160 for (
unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
161 if (AsmTokOffsets[i] >= LastCharOffset)
163 TempToks.push_back(AsmToks[i]);
168 ClangAsmParserCallback::translateLocation(
const llvm::SourceMgr &LSM,
173 const llvm::MemoryBuffer *LBuf =
174 LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
175 unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
178 const unsigned *TokOffsetPtr =
179 std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),
Offset);
180 unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
181 unsigned TokOffset = *TokOffsetPtr;
187 if (TokIndex < AsmToks.size()) {
188 const Token &
Tok = AsmToks[TokIndex];
195 void ClangAsmParserCallback::handleDiagnostic(
const llvm::SMDiagnostic &D) {
196 const llvm::SourceMgr &LSM = *D.getSourceMgr();
198 TheParser.
Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
203 unsigned &NumLineToksConsumed,
204 bool IsUnevaluatedContext) {
209 Token EndOfStreamTok;
211 EndOfStreamTok.
setKind(EndOfStream);
212 LineToks.push_back(EndOfStreamTok);
215 LineToks.push_back(Tok);
217 PP.EnterTokenStream(LineToks,
true);
225 ParseOptionalCXXScopeSpecifier(SS,
nullptr,
false);
233 if (Tok.
is(tok::kw_this)) {
234 Result = ParseCXXThis();
237 Invalid = ParseUnqualifiedId(SS,
242 nullptr, &TemplateKWLoc, Id);
244 Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
245 IsUnevaluatedContext);
250 while (Result.
isUsable() && Tok.
is(tok::period)) {
251 Token IdTok = PP.LookAhead(0);
252 if (IdTok.
isNot(tok::identifier))
257 Result = Actions.LookupInlineAsmVarDeclField(Result.
get(), Id->
getName(),
262 unsigned LineIndex = 0;
263 if (Tok.
is(EndOfStream)) {
264 LineIndex = LineToks.size() - 2;
266 while (LineToks[LineIndex].getLocation() != Tok.
getLocation()) {
268 assert(LineIndex < LineToks.size() - 2);
274 if (Invalid || Tok.
is(EndOfStream)) {
275 NumLineToksConsumed = LineToks.size() - 2;
278 NumLineToksConsumed = LineIndex;
283 for (
unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
286 assert(Tok.
is(EndOfStream));
302 assert(!AsmToks.empty() &&
"Didn't expect an empty AsmToks!");
305 bool isNewStatement =
true;
307 for (
unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
308 const Token &Tok = AsmToks[i];
313 isNewStatement =
true;
322 TokOffsets.push_back(Asm.size());
325 if (Tok.
is(tok::kw_asm)) {
328 PP.
Diag(AsmLoc, diag::err_asm_empty);
337 bool SpellingInvalid =
false;
338 Asm += PP.
getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
339 assert(!SpellingInvalid &&
"spelling was invalid after correct parse?");
342 isNewStatement =
false;
349 assert(TokOffsets.size() == AsmToks.size());
357 default:
return false;
360 case tok::kw_volatile:
361 case tok::kw_restrict:
362 case tok::kw___private:
363 case tok::kw___local:
364 case tok::kw___global:
365 case tok::kw___constant:
366 case tok::kw___generic:
367 case tok::kw___read_only:
368 case tok::kw___read_write:
369 case tok::kw___write_only:
376 return TokAfterAsm.
is(tok::l_paren) || TokAfterAsm.
is(tok::kw_goto) ||
400 bool SingleLineMode =
true;
401 unsigned BraceNesting = 0;
402 unsigned short savedBraceCount = BraceCount;
403 bool InAsmComment =
false;
406 unsigned NumTokensRead = 0;
408 bool SkippedStartOfLine =
false;
410 if (Tok.
is(tok::l_brace)) {
412 SingleLineMode =
false;
414 EndLoc = ConsumeBrace();
415 LBraceLocs.push_back(EndLoc);
419 std::pair<FileID, unsigned> ExpAsmLoc =
421 FID = ExpAsmLoc.first;
432 if (!InAsmComment && Tok.
is(tok::l_brace)) {
435 AsmToks.push_back(Tok);
436 EndLoc = ConsumeBrace();
438 LBraceLocs.push_back(EndLoc);
442 }
else if (!InAsmComment && Tok.
is(tok::semi)) {
445 if (!SingleLineMode) {
447 std::pair<FileID, unsigned> ExpSemiLoc =
449 FID = ExpSemiLoc.first;
452 }
else if (SingleLineMode || InAsmComment) {
455 std::pair<FileID, unsigned> ExpLoc =
457 if (ExpLoc.first != FID ||
458 SrcMgr.
getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
463 bool isAsm = Tok.
is(tok::kw_asm);
467 InAsmComment =
false;
471 if (PP.LookAhead(0).is(tok::l_brace))
475 }
else if (Tok.
is(tok::semi)) {
481 }
else if (!InAsmComment && Tok.
is(tok::r_brace)) {
489 if (!InAsmComment && BraceNesting && Tok.
is(tok::r_brace) &&
490 BraceCount == (savedBraceCount + BraceNesting)) {
494 if (SingleLineMode || BraceNesting > 1) {
496 AsmToks.push_back(Tok);
498 EndLoc = ConsumeBrace();
502 if (BraceNesting == 0 && !SingleLineMode)
505 LBraceLocs.pop_back();
520 if (SkippedStartOfLine)
522 AsmToks.push_back(Tok);
527 SkippedStartOfLine =
false;
530 if (BraceNesting && BraceCount != savedBraceCount) {
532 for (
unsigned i = 0; i < BraceNesting; ++i) {
533 Diag(Tok, diag::err_expected) << tok::r_brace;
534 Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
535 LBraceLocs.pop_back();
538 }
else if (NumTokensRead == 0) {
540 Diag(Tok, diag::err_expected) << tok::l_brace;
550 const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
551 llvm::Triple::ArchType ArchTy = TheTriple.getArch();
552 const std::string &TT = TheTriple.getTriple();
554 bool UnsupportedArch =
555 (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
556 if (UnsupportedArch) {
557 Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
560 TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
562 Diag(AsmLoc, diag::err_msasm_unable_to_create_target) <<
Error;
565 assert(!LBraceLocs.empty() &&
"Should have at least one location here");
569 if (!TheTarget || AsmToks.empty()) {
570 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
572 ConstraintRefs, ClobberRefs, Exprs, EndLoc);
581 const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts();
582 std::string FeaturesStr =
585 std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
586 std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
588 std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
589 std::unique_ptr<llvm::MCObjectFileInfo> MOFI(
new llvm::MCObjectFileInfo());
590 std::unique_ptr<llvm::MCSubtargetInfo> STI(
591 TheTarget->createMCSubtargetInfo(TT, TO.
CPU, FeaturesStr));
593 llvm::SourceMgr TempSrcMgr;
594 llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
595 MOFI->InitMCObjectFileInfo(TheTriple,
false, Ctx);
596 std::unique_ptr<llvm::MemoryBuffer> Buffer =
597 llvm::MemoryBuffer::getMemBuffer(AsmString,
"<MS inline asm>");
600 TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
602 std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
603 std::unique_ptr<llvm::MCAsmParser>
Parser(
604 createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
607 llvm::MCTargetOptions MCOptions;
608 std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
609 TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
611 std::unique_ptr<llvm::MCInstPrinter> IP(
612 TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
615 Parser->setAssemblerDialect(1);
616 Parser->setTargetParser(*TargetParser.get());
617 Parser->setParsingInlineAsm(
true);
618 TargetParser->setParsingInlineAsm(
true);
620 ClangAsmParserCallback Callback(*
this, AsmLoc, AsmString, AsmToks,
622 TargetParser->setSemaCallback(&Callback);
623 TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
628 std::string AsmStringIR;
632 if (Parser->parseMSInlineAsm(AsmLoc.
getPtrEncoding(), AsmStringIR, NumOutputs,
633 NumInputs, OpExprs, Constraints, Clobbers,
634 MII.get(), IP.get(), Callback))
639 llvm::erase_if(Clobbers, [](
const std::string &
C) {
640 return C ==
"fpsr" || C ==
"mxcsr";
644 ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
647 unsigned NumExprs = NumOutputs + NumInputs;
648 ConstraintRefs.resize(NumExprs);
649 Exprs.resize(NumExprs);
650 for (
unsigned i = 0, e = NumExprs; i != e; ++i) {
651 Expr *OpExpr =
static_cast<Expr *
>(OpExprs[i].first);
656 if (OpExprs[i].second)
658 Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
660 ConstraintRefs[i] = StringRef(Constraints[i]);
665 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
666 NumOutputs, NumInputs, ConstraintRefs,
667 ClobberRefs, Exprs, EndLoc);
689 StmtResult Parser::ParseAsmStatement(
bool &msAsm) {
690 assert(Tok.
is(tok::kw_asm) &&
"Not an asm stmt");
695 return ParseMicrosoftAsmStatement(AsmLoc);
700 ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
704 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"const";
706 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"restrict";
709 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"_Atomic";
715 if (Tok.
is(tok::kw_goto)) {
716 Diag(Tok, diag::err_asm_goto_not_supported_yet);
717 SkipUntil(tok::r_paren, StopAtSemi);
721 if (Tok.
isNot(tok::l_paren)) {
722 Diag(Tok, diag::err_expected_lparen_after) <<
"asm";
723 SkipUntil(tok::r_paren, StopAtSemi);
729 ExprResult AsmString(ParseAsmStringLiteral());
733 if (!(getLangOpts().GNUAsm || AsmString.
isInvalid())) {
734 const auto *SL = cast<StringLiteral>(AsmString.
get());
735 if (!SL->getString().trim().empty())
736 Diag(Loc, diag::err_gnu_inline_asm_disabled);
746 ExprVector Constraints;
750 if (Tok.
is(tok::r_paren)) {
753 return Actions.ActOnGCCAsmStmt(AsmLoc,
true, isVolatile,
755 Constraints, Exprs, AsmString.
get(),
760 bool AteExtraColon =
false;
761 if (Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
763 AteExtraColon = Tok.
is(tok::coloncolon);
766 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
770 unsigned NumOutputs = Names.size();
773 if (AteExtraColon || Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
776 AteExtraColon =
false;
778 AteExtraColon = Tok.
is(tok::coloncolon);
782 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
786 assert(Names.size() == Constraints.size() &&
787 Constraints.size() == Exprs.size() &&
"Input operand size mismatch!");
789 unsigned NumInputs = Names.size() - NumOutputs;
792 if (AteExtraColon || Tok.
is(tok::colon)) {
797 if (Tok.
isNot(tok::r_paren)) {
804 Clobbers.push_back(Clobber.
get());
806 if (!TryConsumeToken(tok::comma))
813 return Actions.ActOnGCCAsmStmt(
814 AsmLoc,
false, isVolatile, NumOutputs, NumInputs, Names.data(),
835 if (!isTokenStringLiteral() && Tok.
isNot(tok::l_square))
840 if (Tok.
is(tok::l_square)) {
844 if (Tok.
isNot(tok::identifier)) {
845 Diag(Tok, diag::err_expected) << tok::identifier;
846 SkipUntil(tok::r_paren, StopAtSemi);
856 Names.push_back(
nullptr);
858 ExprResult Constraint(ParseAsmStringLiteral());
860 SkipUntil(tok::r_paren, StopAtSemi);
863 Constraints.push_back(Constraint.
get());
865 if (Tok.
isNot(tok::l_paren)) {
866 Diag(Tok, diag::err_expected_lparen_after) <<
"asm operand";
867 SkipUntil(tok::r_paren, StopAtSemi);
874 ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
877 SkipUntil(tok::r_paren, StopAtSemi);
880 Exprs.push_back(Res.
get());
882 if (!TryConsumeToken(tok::comma))
Defines the clang::ASTContext interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
void FillInlineAsmIdentifierInfo(Expr *Res, llvm::InlineAsmIdentifierInfo &Info)
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
SourceLocation getCloseLocation() const
void setFlag(TokenFlags Flag)
Set the specified flag.
Parser - This implements a parser for the C family of languages.
ActionResult< Stmt * > StmtResult
Options for controlling the target.
tok::TokenKind getKind() const
static bool isGCCAsmStatement(const Token &TokAfterAsm)
One of these records is kept for each identifier that is lexed.
Token - This structure provides full information about a lexed token.
void setKind(tok::TokenKind K)
RAII class that helps handle the parsing of an open/close delimiter pair, such as braces { ...
LabelDecl * GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate)
std::pair< FileID, unsigned > getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
Represents a C++ unqualified-id that has been parsed.
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
Defines the Diagnostic-related interfaces.
Represents a C++ nested-name-specifier or a global scope specifier.
This represents one expression.
static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, ArrayRef< Token > AsmToks, SmallVectorImpl< unsigned > &TokOffsets, SmallString< 512 > &Asm)
Turn a sequence of our tokens back into a string that we can hand to the MC asm parser.
Sema & getActions() const
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
The result type of a method or function.
std::string CPU
If given, the name of the target CPU to generate code for.
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Represents the declaration of a label.
ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl< Token > &LineToks, unsigned &NumLineToksConsumed, bool IsUnevaluated)
Parse an identifier in an MS-style inline assembly block.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
std::vector< std::string > Features
The list of target specific features to enable or disable – this should be a list of strings startin...
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc)
StringRef getName() const
Return the actual identifier string.
static bool isTypeQualifier(const Token &Tok)
isTypeQualifier - Return true if the current token could be the start of a type-qualifier-list.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isNot(tok::TokenKind K) const
Dataflow Directional Tag Classes.
StringRef getMSAsmLabel() const
unsigned getTypeQualifiers() const
getTypeQualifiers - Return a set of TQs.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Captures information about "declaration specifiers".
Defines the clang::TargetInfo interface.
void clearFlag(TokenFlags Flag)
Unset the specified flag.
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const
Forwarding function for diagnostics.
This class handles loading and caching of source files into memory.
void startToken()
Reset all flags to cleared.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
static OMPLinearClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef< Expr *> VL, ArrayRef< Expr *> PL, ArrayRef< Expr *> IL, Expr *Step, Expr *CalcStep, Stmt *PreInit, Expr *PostUpdate)
Creates clause with a list of variables VL and a linear step Step.
void * getPtrEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) pointer encoding for it...