ParseStmtAsm.cpp 33 KB

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