From 0f89fac7a51d489eb4300fcb0159e2b6f2ba5556 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sun, 6 Jul 2014 05:26:54 +0000 Subject: [PATCH] Add support for nested blocks in Microsoft inline assembly This fixes http://llvm.org/PR20204. llvm-svn: 212389 --- clang/lib/Parse/ParseStmtAsm.cpp | 66 ++++++++++++++++++------- clang/test/CodeGen/ms-inline-asm-64.c | 4 +- clang/test/CodeGen/ms-inline-asm.c | 11 +++-- clang/test/Parser/ms-inline-asm-nested-braces.c | 9 ++++ clang/test/Parser/ms-inline-asm.c | 11 +++++ 5 files changed, 80 insertions(+), 21 deletions(-) create mode 100644 clang/test/Parser/ms-inline-asm-nested-braces.c diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index 6f16614..de299fd 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -322,19 +322,21 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SourceLocation EndLoc = AsmLoc; SmallVector AsmToks; - bool InBraces = false; + unsigned BraceNesting = 0; unsigned short savedBraceCount = 0; bool InAsmComment = false; FileID FID; unsigned LineNo = 0; unsigned NumTokensRead = 0; - SourceLocation LBraceLoc; + SmallVector LBraceLocs; + bool SkippedStartOfLine = false; if (Tok.is(tok::l_brace)) { // Braced inline asm: consume the opening brace. - InBraces = true; + BraceNesting = 1; savedBraceCount = BraceCount; - EndLoc = LBraceLoc = ConsumeBrace(); + EndLoc = ConsumeBrace(); + LBraceLocs.push_back(EndLoc); ++NumTokensRead; } else { // Single-line inline asm; compute which line it is on. @@ -342,6 +344,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SrcMgr.getDecomposedExpansionLoc(EndLoc); FID = ExpAsmLoc.first; LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); + LBraceLocs.push_back(SourceLocation()); } SourceLocation TokLoc = Tok.getLocation(); @@ -350,17 +353,26 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (isEofOrEom()) break; - if (!InAsmComment && Tok.is(tok::semi)) { + if (!InAsmComment && Tok.is(tok::l_brace)) { + // Consume the opening brace. + SkippedStartOfLine = Tok.isAtStartOfLine(); + EndLoc = ConsumeBrace(); + BraceNesting++; + LBraceLocs.push_back(EndLoc); + TokLoc = Tok.getLocation(); + ++NumTokensRead; + continue; + } else if (!InAsmComment && Tok.is(tok::semi)) { // A semicolon in an asm is the start of a comment. InAsmComment = true; - if (InBraces) { + if (BraceNesting) { // Compute which line the comment is on. std::pair ExpSemiLoc = SrcMgr.getDecomposedExpansionLoc(TokLoc); FID = ExpSemiLoc.first; LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); } - } else if (!InBraces || InAsmComment) { + } else if (!BraceNesting || InAsmComment) { // If end-of-line is significant, check whether this token is on a // new line. std::pair ExpLoc = @@ -368,7 +380,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (ExpLoc.first != FID || SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { // If this is a single-line __asm, we're done. - if (!InBraces) + if (!BraceNesting) break; // We're no longer in a comment. InAsmComment = false; @@ -379,11 +391,21 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { break; } } - if (!InAsmComment && InBraces && Tok.is(tok::r_brace) && - BraceCount == (savedBraceCount + 1)) { - // Consume the closing brace, and finish + if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) && + BraceCount == (savedBraceCount + BraceNesting)) { + // Consume the closing brace. + SkippedStartOfLine = Tok.isAtStartOfLine(); EndLoc = ConsumeBrace(); - break; + BraceNesting--; + // Finish if all of the opened braces in the inline asm section were consumed. + if (BraceNesting == 0) + break; + else { + LBraceLocs.pop_back(); + TokLoc = Tok.getLocation(); + ++NumTokensRead; + continue; + } } // Consume the next token; make sure we don't modify the brace count etc. @@ -392,17 +414,25 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (InAsmComment) PP.Lex(Tok); else { + // Set the token as the start of line if we skipped the original start + // of line token in case it was a nested brace. + if (SkippedStartOfLine) + Tok.setFlag(Token::StartOfLine); AsmToks.push_back(Tok); ConsumeAnyToken(); } TokLoc = Tok.getLocation(); ++NumTokensRead; + SkippedStartOfLine = false; } while (1); - if (InBraces && BraceCount != savedBraceCount) { + if (BraceNesting && BraceCount != savedBraceCount) { // __asm without closing brace (this can happen at EOF). - Diag(Tok, diag::err_expected) << tok::r_brace; - Diag(LBraceLoc, diag::note_matching) << tok::l_brace; + for (unsigned i = 0; i < BraceNesting; ++i) { + Diag(Tok, diag::err_expected) << tok::r_brace; + Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace; + LBraceLocs.pop_back(); + } return StmtError(); } else if (NumTokensRead == 0) { // Empty __asm. @@ -431,10 +461,12 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error; } + assert(!LBraceLocs.empty() && "Should have at least one location here"); + // If we don't support assembly, or the assembly is empty, we don't // need to instantiate the AsmParser, etc. if (!TheTarget || AsmToks.empty()) { - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(), + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), /*NumOutputs*/ 0, /*NumInputs*/ 0, ConstraintRefs, ClobberRefs, Exprs, EndLoc); } @@ -523,7 +555,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { } // FIXME: We should be passing source locations for better diagnostics. - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR, + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR, NumOutputs, NumInputs, ConstraintRefs, ClobberRefs, Exprs, EndLoc); } diff --git a/clang/test/CodeGen/ms-inline-asm-64.c b/clang/test/CodeGen/ms-inline-asm-64.c index 69066aa8..d6f6e2e 100644 --- a/clang/test/CodeGen/ms-inline-asm-64.c +++ b/clang/test/CodeGen/ms-inline-asm-64.c @@ -37,7 +37,9 @@ int t4() { foo.b = 2; __asm { lea ebx, foo - mov eax, [ebx].foo.a + { + mov eax, [ebx].foo.a + } mov [ebx].foo.b, ecx } return foo.b; diff --git a/clang/test/CodeGen/ms-inline-asm.c b/clang/test/CodeGen/ms-inline-asm.c index 3836ddd..3b55b50 100644 --- a/clang/test/CodeGen/ms-inline-asm.c +++ b/clang/test/CodeGen/ms-inline-asm.c @@ -52,6 +52,11 @@ void t7() { __asm { int 0x2c ; } asm comments are fun! }{ } + __asm { + { + int 0x2c ; } asm comments are fun! }{ + } + } __asm {} // CHECK: t7 // CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"() @@ -73,8 +78,8 @@ int t8() { void t9() { __asm { push ebx - mov ebx, 0x07 - pop ebx + { mov ebx, 0x07 } + __asm { pop ebx } } // CHECK: t9 // CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"() @@ -129,7 +134,7 @@ void t14() { unsigned i = 1, j = 2; __asm { .if 1 - mov eax, i + { mov eax, i } .else mov ebx, j .endif diff --git a/clang/test/Parser/ms-inline-asm-nested-braces.c b/clang/test/Parser/ms-inline-asm-nested-braces.c new file mode 100644 index 0000000..58b055b --- /dev/null +++ b/clang/test/Parser/ms-inline-asm-nested-braces.c @@ -0,0 +1,9 @@ +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -verify -fasm-blocks + +int t_fail() { // expected-note {{to match this}} + __asm + { // expected-note {{to match this}} + { // expected-note {{to match this}} + { + } // expected-error 3 {{expected}} diff --git a/clang/test/Parser/ms-inline-asm.c b/clang/test/Parser/ms-inline-asm.c index a9c15cf..564f008 100644 --- a/clang/test/Parser/ms-inline-asm.c +++ b/clang/test/Parser/ms-inline-asm.c @@ -34,6 +34,17 @@ void t8() { void t9() { __asm nop __asm nop ; __asm nop } +void t10() { + __asm { + mov eax, 0 + __asm { + mov eax, 1 + { + mov eax, 2 + } + } + } +} int t_fail() { // expected-note {{to match this}} __asm __asm { // expected-error 3 {{expected}} expected-note {{to match this}} -- 2.7.4