ParseStmtAsm.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  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/Parse/Parser.h"
  13. #include "clang/AST/ASTContext.h"
  14. #include "clang/Basic/Diagnostic.h"
  15. #include "clang/Basic/TargetInfo.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/Support/SourceMgr.h"
  31. #include "llvm/Support/TargetRegistry.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, nullptr, /*EnteringContext=*/false);
  192. }
  193. // Require an identifier here.
  194. SourceLocation TemplateKWLoc;
  195. UnqualifiedId Id;
  196. bool Invalid = true;
  197. ExprResult Result;
  198. if (Tok.is(tok::kw_this)) {
  199. Result = ParseCXXThis();
  200. Invalid = false;
  201. } else {
  202. Invalid = ParseUnqualifiedId(SS,
  203. /*EnteringContext=*/false,
  204. /*AllowDestructorName=*/false,
  205. /*AllowConstructorName=*/false,
  206. /*AllowDeductionGuide=*/false,
  207. /*ObjectType=*/nullptr, &TemplateKWLoc, Id);
  208. // Perform the lookup.
  209. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
  210. IsUnevaluatedContext);
  211. }
  212. // While the next two tokens are 'period' 'identifier', repeatedly parse it as
  213. // a field access. We have to avoid consuming assembler directives that look
  214. // like '.' 'else'.
  215. while (Result.isUsable() && Tok.is(tok::period)) {
  216. Token IdTok = PP.LookAhead(0);
  217. if (IdTok.isNot(tok::identifier))
  218. break;
  219. ConsumeToken(); // Consume the period.
  220. IdentifierInfo *Id = Tok.getIdentifierInfo();
  221. ConsumeToken(); // Consume the identifier.
  222. Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
  223. Tok.getLocation());
  224. }
  225. // Figure out how many tokens we are into LineToks.
  226. unsigned LineIndex = 0;
  227. if (Tok.is(EndOfStream)) {
  228. LineIndex = LineToks.size() - 2;
  229. } else {
  230. while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
  231. LineIndex++;
  232. assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
  233. }
  234. }
  235. // If we've run into the poison token we inserted before, or there
  236. // was a parsing error, then claim the entire line.
  237. if (Invalid || Tok.is(EndOfStream)) {
  238. NumLineToksConsumed = LineToks.size() - 2;
  239. } else {
  240. // Otherwise, claim up to the start of the next token.
  241. NumLineToksConsumed = LineIndex;
  242. }
  243. // Finally, restore the old parsing state by consuming all the tokens we
  244. // staged before, implicitly killing off the token-lexer we pushed.
  245. for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
  246. ConsumeAnyToken();
  247. }
  248. assert(Tok.is(EndOfStream));
  249. ConsumeToken();
  250. // Leave LineToks in its original state.
  251. LineToks.pop_back();
  252. LineToks.pop_back();
  253. return Result;
  254. }
  255. /// Turn a sequence of our tokens back into a string that we can hand
  256. /// to the MC asm parser.
  257. static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,
  258. ArrayRef<Token> AsmToks,
  259. SmallVectorImpl<unsigned> &TokOffsets,
  260. SmallString<512> &Asm) {
  261. assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");
  262. // Is this the start of a new assembly statement?
  263. bool isNewStatement = true;
  264. for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
  265. const Token &Tok = AsmToks[i];
  266. // Start each new statement with a newline and a tab.
  267. if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
  268. Asm += "\n\t";
  269. isNewStatement = true;
  270. }
  271. // Preserve the existence of leading whitespace except at the
  272. // start of a statement.
  273. if (!isNewStatement && Tok.hasLeadingSpace())
  274. Asm += ' ';
  275. // Remember the offset of this token.
  276. TokOffsets.push_back(Asm.size());
  277. // Don't actually write '__asm' into the assembly stream.
  278. if (Tok.is(tok::kw_asm)) {
  279. // Complain about __asm at the end of the stream.
  280. if (i + 1 == e) {
  281. PP.Diag(AsmLoc, diag::err_asm_empty);
  282. return true;
  283. }
  284. continue;
  285. }
  286. // Append the spelling of the token.
  287. SmallString<32> SpellingBuffer;
  288. bool SpellingInvalid = false;
  289. Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
  290. assert(!SpellingInvalid && "spelling was invalid after correct parse?");
  291. // We are no longer at the start of a statement.
  292. isNewStatement = false;
  293. }
  294. // Ensure that the buffer is null-terminated.
  295. Asm.push_back('\0');
  296. Asm.pop_back();
  297. assert(TokOffsets.size() == AsmToks.size());
  298. return false;
  299. }
  300. /// isTypeQualifier - Return true if the current token could be the
  301. /// start of a type-qualifier-list.
  302. static bool isTypeQualifier(const Token &Tok) {
  303. switch (Tok.getKind()) {
  304. default: return false;
  305. // type-qualifier
  306. case tok::kw_const:
  307. case tok::kw_volatile:
  308. case tok::kw_restrict:
  309. case tok::kw___private:
  310. case tok::kw___local:
  311. case tok::kw___global:
  312. case tok::kw___constant:
  313. case tok::kw___generic:
  314. case tok::kw___read_only:
  315. case tok::kw___read_write:
  316. case tok::kw___write_only:
  317. return true;
  318. }
  319. }
  320. // Determine if this is a GCC-style asm statement.
  321. static bool isGCCAsmStatement(const Token &TokAfterAsm) {
  322. return TokAfterAsm.is(tok::l_paren) || TokAfterAsm.is(tok::kw_goto) ||
  323. isTypeQualifier(TokAfterAsm);
  324. }
  325. /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
  326. /// this routine is called to collect the tokens for an MS asm statement.
  327. ///
  328. /// [MS] ms-asm-statement:
  329. /// ms-asm-block
  330. /// ms-asm-block ms-asm-statement
  331. ///
  332. /// [MS] ms-asm-block:
  333. /// '__asm' ms-asm-line '\n'
  334. /// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
  335. ///
  336. /// [MS] ms-asm-instruction-block
  337. /// ms-asm-line
  338. /// ms-asm-line '\n' ms-asm-instruction-block
  339. ///
  340. StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
  341. SourceManager &SrcMgr = PP.getSourceManager();
  342. SourceLocation EndLoc = AsmLoc;
  343. SmallVector<Token, 4> AsmToks;
  344. bool SingleLineMode = true;
  345. unsigned BraceNesting = 0;
  346. unsigned short savedBraceCount = BraceCount;
  347. bool InAsmComment = false;
  348. FileID FID;
  349. unsigned LineNo = 0;
  350. unsigned NumTokensRead = 0;
  351. SmallVector<SourceLocation, 4> LBraceLocs;
  352. bool SkippedStartOfLine = false;
  353. if (Tok.is(tok::l_brace)) {
  354. // Braced inline asm: consume the opening brace.
  355. SingleLineMode = false;
  356. BraceNesting = 1;
  357. EndLoc = ConsumeBrace();
  358. LBraceLocs.push_back(EndLoc);
  359. ++NumTokensRead;
  360. } else {
  361. // Single-line inline asm; compute which line it is on.
  362. std::pair<FileID, unsigned> ExpAsmLoc =
  363. SrcMgr.getDecomposedExpansionLoc(EndLoc);
  364. FID = ExpAsmLoc.first;
  365. LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
  366. LBraceLocs.push_back(SourceLocation());
  367. }
  368. SourceLocation TokLoc = Tok.getLocation();
  369. do {
  370. // If we hit EOF, we're done, period.
  371. if (isEofOrEom())
  372. break;
  373. if (!InAsmComment && Tok.is(tok::l_brace)) {
  374. // Consume the opening brace.
  375. SkippedStartOfLine = Tok.isAtStartOfLine();
  376. AsmToks.push_back(Tok);
  377. EndLoc = ConsumeBrace();
  378. BraceNesting++;
  379. LBraceLocs.push_back(EndLoc);
  380. TokLoc = Tok.getLocation();
  381. ++NumTokensRead;
  382. continue;
  383. } else if (!InAsmComment && Tok.is(tok::semi)) {
  384. // A semicolon in an asm is the start of a comment.
  385. InAsmComment = true;
  386. if (!SingleLineMode) {
  387. // Compute which line the comment is on.
  388. std::pair<FileID, unsigned> ExpSemiLoc =
  389. SrcMgr.getDecomposedExpansionLoc(TokLoc);
  390. FID = ExpSemiLoc.first;
  391. LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
  392. }
  393. } else if (SingleLineMode || InAsmComment) {
  394. // If end-of-line is significant, check whether this token is on a
  395. // new line.
  396. std::pair<FileID, unsigned> ExpLoc =
  397. SrcMgr.getDecomposedExpansionLoc(TokLoc);
  398. if (ExpLoc.first != FID ||
  399. SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
  400. // If this is a single-line __asm, we're done, except if the next
  401. // line is MS-style asm too, in which case we finish a comment
  402. // if needed and then keep processing the next line as a single
  403. // line __asm.
  404. bool isAsm = Tok.is(tok::kw_asm);
  405. if (SingleLineMode && (!isAsm || isGCCAsmStatement(NextToken())))
  406. break;
  407. // We're no longer in a comment.
  408. InAsmComment = false;
  409. if (isAsm) {
  410. // If this is a new __asm {} block we want to process it separately
  411. // from the single-line __asm statements
  412. if (PP.LookAhead(0).is(tok::l_brace))
  413. break;
  414. LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second);
  415. SkippedStartOfLine = Tok.isAtStartOfLine();
  416. } else if (Tok.is(tok::semi)) {
  417. // A multi-line asm-statement, where next line is a comment
  418. InAsmComment = true;
  419. FID = ExpLoc.first;
  420. LineNo = SrcMgr.getLineNumber(FID, ExpLoc.second);
  421. }
  422. } else if (!InAsmComment && Tok.is(tok::r_brace)) {
  423. // In MSVC mode, braces only participate in brace matching and
  424. // separating the asm statements. This is an intentional
  425. // departure from the Apple gcc behavior.
  426. if (!BraceNesting)
  427. break;
  428. }
  429. }
  430. if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
  431. BraceCount == (savedBraceCount + BraceNesting)) {
  432. // Consume the closing brace.
  433. SkippedStartOfLine = Tok.isAtStartOfLine();
  434. // Don't want to add the closing brace of the whole asm block
  435. if (SingleLineMode || BraceNesting > 1) {
  436. Tok.clearFlag(Token::LeadingSpace);
  437. AsmToks.push_back(Tok);
  438. }
  439. EndLoc = ConsumeBrace();
  440. BraceNesting--;
  441. // Finish if all of the opened braces in the inline asm section were
  442. // consumed.
  443. if (BraceNesting == 0 && !SingleLineMode)
  444. break;
  445. else {
  446. LBraceLocs.pop_back();
  447. TokLoc = Tok.getLocation();
  448. ++NumTokensRead;
  449. continue;
  450. }
  451. }
  452. // Consume the next token; make sure we don't modify the brace count etc.
  453. // if we are in a comment.
  454. EndLoc = TokLoc;
  455. if (InAsmComment)
  456. PP.Lex(Tok);
  457. else {
  458. // Set the token as the start of line if we skipped the original start
  459. // of line token in case it was a nested brace.
  460. if (SkippedStartOfLine)
  461. Tok.setFlag(Token::StartOfLine);
  462. AsmToks.push_back(Tok);
  463. ConsumeAnyToken();
  464. }
  465. TokLoc = Tok.getLocation();
  466. ++NumTokensRead;
  467. SkippedStartOfLine = false;
  468. } while (1);
  469. if (BraceNesting && BraceCount != savedBraceCount) {
  470. // __asm without closing brace (this can happen at EOF).
  471. for (unsigned i = 0; i < BraceNesting; ++i) {
  472. Diag(Tok, diag::err_expected) << tok::r_brace;
  473. Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
  474. LBraceLocs.pop_back();
  475. }
  476. return StmtError();
  477. } else if (NumTokensRead == 0) {
  478. // Empty __asm.
  479. Diag(Tok, diag::err_expected) << tok::l_brace;
  480. return StmtError();
  481. }
  482. // Okay, prepare to use MC to parse the assembly.
  483. SmallVector<StringRef, 4> ConstraintRefs;
  484. SmallVector<Expr *, 4> Exprs;
  485. SmallVector<StringRef, 4> ClobberRefs;
  486. // We need an actual supported target.
  487. const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
  488. llvm::Triple::ArchType ArchTy = TheTriple.getArch();
  489. const std::string &TT = TheTriple.getTriple();
  490. const llvm::Target *TheTarget = nullptr;
  491. bool UnsupportedArch =
  492. (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
  493. if (UnsupportedArch) {
  494. Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
  495. } else {
  496. std::string Error;
  497. TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
  498. if (!TheTarget)
  499. Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
  500. }
  501. assert(!LBraceLocs.empty() && "Should have at least one location here");
  502. // If we don't support assembly, or the assembly is empty, we don't
  503. // need to instantiate the AsmParser, etc.
  504. if (!TheTarget || AsmToks.empty()) {
  505. return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
  506. /*NumOutputs*/ 0, /*NumInputs*/ 0,
  507. ConstraintRefs, ClobberRefs, Exprs, EndLoc);
  508. }
  509. // Expand the tokens into a string buffer.
  510. SmallString<512> AsmString;
  511. SmallVector<unsigned, 8> TokOffsets;
  512. if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
  513. return StmtError();
  514. const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts();
  515. std::string FeaturesStr =
  516. llvm::join(TO.Features.begin(), TO.Features.end(), ",");
  517. std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
  518. std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
  519. // Get the instruction descriptor.
  520. std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
  521. std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
  522. std::unique_ptr<llvm::MCSubtargetInfo> STI(
  523. TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr));
  524. llvm::SourceMgr TempSrcMgr;
  525. llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
  526. MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx);
  527. std::unique_ptr<llvm::MemoryBuffer> Buffer =
  528. llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
  529. // Tell SrcMgr about this buffer, which is what the parser will pick up.
  530. TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
  531. std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
  532. std::unique_ptr<llvm::MCAsmParser> Parser(
  533. createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
  534. // FIXME: init MCOptions from sanitizer flags here.
  535. llvm::MCTargetOptions MCOptions;
  536. std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
  537. TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
  538. std::unique_ptr<llvm::MCInstPrinter> IP(
  539. TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
  540. // Change to the Intel dialect.
  541. Parser->setAssemblerDialect(1);
  542. Parser->setTargetParser(*TargetParser.get());
  543. Parser->setParsingInlineAsm(true);
  544. TargetParser->setParsingInlineAsm(true);
  545. ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,
  546. TokOffsets);
  547. TargetParser->setSemaCallback(&Callback);
  548. TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
  549. &Callback);
  550. unsigned NumOutputs;
  551. unsigned NumInputs;
  552. std::string AsmStringIR;
  553. SmallVector<std::pair<void *, bool>, 4> OpExprs;
  554. SmallVector<std::string, 4> Constraints;
  555. SmallVector<std::string, 4> Clobbers;
  556. if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
  557. NumInputs, OpExprs, Constraints, Clobbers,
  558. MII.get(), IP.get(), Callback))
  559. return StmtError();
  560. // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber
  561. // constraints. Clang always adds fpsr to the clobber list anyway.
  562. llvm::erase_if(Clobbers, [](const std::string &C) {
  563. return C == "fpsr" || C == "mxcsr";
  564. });
  565. // Build the vector of clobber StringRefs.
  566. ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
  567. // Recast the void pointers and build the vector of constraint StringRefs.
  568. unsigned NumExprs = NumOutputs + NumInputs;
  569. ConstraintRefs.resize(NumExprs);
  570. Exprs.resize(NumExprs);
  571. for (unsigned i = 0, e = NumExprs; i != e; ++i) {
  572. Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
  573. if (!OpExpr)
  574. return StmtError();
  575. // Need address of variable.
  576. if (OpExprs[i].second)
  577. OpExpr =
  578. Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
  579. ConstraintRefs[i] = StringRef(Constraints[i]);
  580. Exprs[i] = OpExpr;
  581. }
  582. // FIXME: We should be passing source locations for better diagnostics.
  583. return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
  584. NumOutputs, NumInputs, ConstraintRefs,
  585. ClobberRefs, Exprs, EndLoc);
  586. }
  587. /// ParseAsmStatement - Parse a GNU extended asm statement.
  588. /// asm-statement:
  589. /// gnu-asm-statement
  590. /// ms-asm-statement
  591. ///
  592. /// [GNU] gnu-asm-statement:
  593. /// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
  594. ///
  595. /// [GNU] asm-argument:
  596. /// asm-string-literal
  597. /// asm-string-literal ':' asm-operands[opt]
  598. /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
  599. /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
  600. /// ':' asm-clobbers
  601. ///
  602. /// [GNU] asm-clobbers:
  603. /// asm-string-literal
  604. /// asm-clobbers ',' asm-string-literal
  605. ///
  606. StmtResult Parser::ParseAsmStatement(bool &msAsm) {
  607. assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
  608. SourceLocation AsmLoc = ConsumeToken();
  609. if (getLangOpts().AsmBlocks && !isGCCAsmStatement(Tok)) {
  610. msAsm = true;
  611. return ParseMicrosoftAsmStatement(AsmLoc);
  612. }
  613. DeclSpec DS(AttrFactory);
  614. SourceLocation Loc = Tok.getLocation();
  615. ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
  616. // GNU asms accept, but warn, about type-qualifiers other than volatile.
  617. if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
  618. Diag(Loc, diag::warn_asm_qualifier_ignored) << "const";
  619. if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
  620. Diag(Loc, diag::warn_asm_qualifier_ignored) << "restrict";
  621. // FIXME: Once GCC supports _Atomic, check whether it permits it here.
  622. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
  623. Diag(Loc, diag::warn_asm_qualifier_ignored) << "_Atomic";
  624. // Remember if this was a volatile asm.
  625. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
  626. // Remember if this was a goto asm.
  627. bool isGotoAsm = false;
  628. if (Tok.is(tok::kw_goto)) {
  629. isGotoAsm = true;
  630. ConsumeToken();
  631. }
  632. if (Tok.isNot(tok::l_paren)) {
  633. Diag(Tok, diag::err_expected_lparen_after) << "asm";
  634. SkipUntil(tok::r_paren, StopAtSemi);
  635. return StmtError();
  636. }
  637. BalancedDelimiterTracker T(*this, tok::l_paren);
  638. T.consumeOpen();
  639. ExprResult AsmString(ParseAsmStringLiteral());
  640. // Check if GNU-style InlineAsm is disabled.
  641. // Error on anything other than empty string.
  642. if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) {
  643. const auto *SL = cast<StringLiteral>(AsmString.get());
  644. if (!SL->getString().trim().empty())
  645. Diag(Loc, diag::err_gnu_inline_asm_disabled);
  646. }
  647. if (AsmString.isInvalid()) {
  648. // Consume up to and including the closing paren.
  649. T.skipToEnd();
  650. return StmtError();
  651. }
  652. SmallVector<IdentifierInfo *, 4> Names;
  653. ExprVector Constraints;
  654. ExprVector Exprs;
  655. ExprVector Clobbers;
  656. if (Tok.is(tok::r_paren)) {
  657. // We have a simple asm expression like 'asm("foo")'.
  658. T.consumeClose();
  659. return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
  660. /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
  661. Constraints, Exprs, AsmString.get(),
  662. Clobbers, /*NumLabels*/ 0,
  663. T.getCloseLocation());
  664. }
  665. // Parse Outputs, if present.
  666. bool AteExtraColon = false;
  667. if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
  668. // In C++ mode, parse "::" like ": :".
  669. AteExtraColon = Tok.is(tok::coloncolon);
  670. ConsumeToken();
  671. if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) {
  672. Diag(Tok, diag::err_asm_goto_cannot_have_output);
  673. SkipUntil(tok::r_paren, StopAtSemi);
  674. return StmtError();
  675. }
  676. if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
  677. return StmtError();
  678. }
  679. unsigned NumOutputs = Names.size();
  680. // Parse Inputs, if present.
  681. if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
  682. // In C++ mode, parse "::" like ": :".
  683. if (AteExtraColon)
  684. AteExtraColon = false;
  685. else {
  686. AteExtraColon = Tok.is(tok::coloncolon);
  687. ConsumeToken();
  688. }
  689. if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
  690. return StmtError();
  691. }
  692. assert(Names.size() == Constraints.size() &&
  693. Constraints.size() == Exprs.size() && "Input operand size mismatch!");
  694. unsigned NumInputs = Names.size() - NumOutputs;
  695. // Parse the clobbers, if present.
  696. if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
  697. if (AteExtraColon)
  698. AteExtraColon = false;
  699. else {
  700. AteExtraColon = Tok.is(tok::coloncolon);
  701. ConsumeToken();
  702. }
  703. // Parse the asm-string list for clobbers if present.
  704. if (!AteExtraColon && isTokenStringLiteral()) {
  705. while (1) {
  706. ExprResult Clobber(ParseAsmStringLiteral());
  707. if (Clobber.isInvalid())
  708. break;
  709. Clobbers.push_back(Clobber.get());
  710. if (!TryConsumeToken(tok::comma))
  711. break;
  712. }
  713. }
  714. }
  715. if (!isGotoAsm && (Tok.isNot(tok::r_paren) || AteExtraColon)) {
  716. Diag(Tok, diag::err_expected) << tok::r_paren;
  717. SkipUntil(tok::r_paren, StopAtSemi);
  718. return StmtError();
  719. }
  720. // Parse the goto label, if present.
  721. unsigned NumLabels = 0;
  722. if (AteExtraColon || Tok.is(tok::colon)) {
  723. if (!AteExtraColon)
  724. ConsumeToken();
  725. while (true) {
  726. if (Tok.isNot(tok::identifier)) {
  727. Diag(Tok, diag::err_expected) << tok::identifier;
  728. SkipUntil(tok::r_paren, StopAtSemi);
  729. return StmtError();
  730. }
  731. LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
  732. Tok.getLocation());
  733. Names.push_back(Tok.getIdentifierInfo());
  734. if (!LD) {
  735. SkipUntil(tok::r_paren, StopAtSemi);
  736. return StmtError();
  737. }
  738. ExprResult Res =
  739. Actions.ActOnAddrLabel(Tok.getLocation(), Tok.getLocation(), LD);
  740. Exprs.push_back(Res.get());
  741. NumLabels++;
  742. ConsumeToken();
  743. if (!TryConsumeToken(tok::comma))
  744. break;
  745. }
  746. } else if (isGotoAsm) {
  747. Diag(Tok, diag::err_expected) << tok::colon;
  748. SkipUntil(tok::r_paren, StopAtSemi);
  749. return StmtError();
  750. }
  751. T.consumeClose();
  752. return Actions.ActOnGCCAsmStmt(
  753. AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
  754. Constraints, Exprs, AsmString.get(), Clobbers, NumLabels,
  755. T.getCloseLocation());
  756. }
  757. /// ParseAsmOperands - Parse the asm-operands production as used by
  758. /// asm-statement, assuming the leading ':' token was eaten.
  759. ///
  760. /// [GNU] asm-operands:
  761. /// asm-operand
  762. /// asm-operands ',' asm-operand
  763. ///
  764. /// [GNU] asm-operand:
  765. /// asm-string-literal '(' expression ')'
  766. /// '[' identifier ']' asm-string-literal '(' expression ')'
  767. ///
  768. //
  769. // FIXME: Avoid unnecessary std::string trashing.
  770. bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
  771. SmallVectorImpl<Expr *> &Constraints,
  772. SmallVectorImpl<Expr *> &Exprs) {
  773. // 'asm-operands' isn't present?
  774. if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
  775. return false;
  776. while (1) {
  777. // Read the [id] if present.
  778. if (Tok.is(tok::l_square)) {
  779. BalancedDelimiterTracker T(*this, tok::l_square);
  780. T.consumeOpen();
  781. if (Tok.isNot(tok::identifier)) {
  782. Diag(Tok, diag::err_expected) << tok::identifier;
  783. SkipUntil(tok::r_paren, StopAtSemi);
  784. return true;
  785. }
  786. IdentifierInfo *II = Tok.getIdentifierInfo();
  787. ConsumeToken();
  788. Names.push_back(II);
  789. T.consumeClose();
  790. } else
  791. Names.push_back(nullptr);
  792. ExprResult Constraint(ParseAsmStringLiteral());
  793. if (Constraint.isInvalid()) {
  794. SkipUntil(tok::r_paren, StopAtSemi);
  795. return true;
  796. }
  797. Constraints.push_back(Constraint.get());
  798. if (Tok.isNot(tok::l_paren)) {
  799. Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
  800. SkipUntil(tok::r_paren, StopAtSemi);
  801. return true;
  802. }
  803. // Read the parenthesized expression.
  804. BalancedDelimiterTracker T(*this, tok::l_paren);
  805. T.consumeOpen();
  806. ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
  807. T.consumeClose();
  808. if (Res.isInvalid()) {
  809. SkipUntil(tok::r_paren, StopAtSemi);
  810. return true;
  811. }
  812. Exprs.push_back(Res.get());
  813. // Eat the comma and continue parsing if it exists.
  814. if (!TryConsumeToken(tok::comma))
  815. return false;
  816. }
  817. }