Etch out the code path for MS-style inline assembly.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158325 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index e4d9f0a..97eb4d5 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -550,6 +550,12 @@
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
}
+MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, std::string &asmstr,
+ SourceLocation endloc)
+ : Stmt(MSAsmStmtClass), AsmLoc(asmloc), EndLoc(endloc), AsmStr(asmstr),
+ IsSimple(true), IsVolatile(true) {
+}
+
ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
Stmt *Body, SourceLocation FCL,
SourceLocation RPL)
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 2bd4d76..30548ae 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -429,6 +429,11 @@
OS << ");\n";
}
+void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
+ // FIXME: Implement MS style inline asm statement printer.
+ Indent() << "asm ()";
+}
+
void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
Indent() << "@try";
if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 72b979d..2168b64 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -178,6 +178,11 @@
VisitStringLiteral(S->getClobber(I));
}
+void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
+ // FIXME: Implement MS style inline asm statement profiler.
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitCXXCatchStmt(const CXXCatchStmt *S) {
VisitStmt(S);
VisitType(S->getCaughtType());
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 86046b7..2f06a8e 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -133,6 +133,7 @@
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
+ case Stmt::MSAsmStmtClass: EmitMSAsmStmt(cast<MSAsmStmt>(*S)); break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
@@ -1681,3 +1682,43 @@
EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
}
}
+
+void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) {
+ // Analyze the asm string to decompose it into its pieces. We know that Sema
+ // has already done this, so it is guaranteed to be successful.
+
+ // Get all the output and input constraints together.
+
+ std::vector<llvm::Value*> Args;
+ std::vector<llvm::Type *> ArgTypes;
+ std::string Constraints;
+
+ // Keep track of inout constraints.
+
+ // Append the "input" part of inout constraints last.
+
+ // Clobbers
+
+ // Add machine specific clobbers
+ std::string MachineClobbers = Target.getClobbers();
+ if (!MachineClobbers.empty()) {
+ if (!Constraints.empty())
+ Constraints += ',';
+ Constraints += MachineClobbers;
+ }
+
+ llvm::Type *ResultType = VoidTy;
+
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(ResultType, ArgTypes, false);
+
+ llvm::InlineAsm *IA =
+ llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true);
+ llvm::CallInst *Result = Builder.CreateCall(IA, Args);
+ Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+
+ // Slap the source location of the inline asm into a !srcloc metadata on the
+ // call.
+
+ // Extract all of the register value results from the asm.
+}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index de7e89e..a6d77e3 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1970,6 +1970,7 @@
void EmitCaseStmt(const CaseStmt &S);
void EmitCaseStmtRange(const CaseStmt &S);
void EmitAsmStmt(const AsmStmt &S);
+ void EmitMSAsmStmt(const MSAsmStmt &S);
void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 6652bea..9f49ab5 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -1627,9 +1628,24 @@
/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
/// this routine is called to collect the tokens for an MS asm statement.
+///
+/// [MS] ms-asm-statement:
+/// ms-asm-block
+/// ms-asm-block ms-asm-statement
+///
+/// [MS] ms-asm-block:
+/// '__asm' ms-asm-line '\n'
+/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
+///
+/// [MS] ms-asm-instruction-block
+/// ms-asm-line
+/// ms-asm-line '\n' ms-asm-instruction-block
+///
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
+ SmallVector<Token, 4> AsmToks;
+ SmallVector<unsigned, 4> LineEnds;
do {
bool InBraces = false;
unsigned short savedBraceCount = 0;
@@ -1658,9 +1674,6 @@
// If we hit EOF, we're done, period.
if (Tok.is(tok::eof))
break;
- // When we consume the closing brace, we're done.
- if (InBraces && BraceCount == savedBraceCount)
- break;
if (!InAsmComment && Tok.is(tok::semi)) {
// A semicolon in an asm is the start of a comment.
@@ -1690,8 +1703,15 @@
// does MSVC do here?
break;
}
+ } else if (InBraces && Tok.is(tok::r_brace) &&
+ BraceCount == savedBraceCount + 1) {
+ // Consume the closing brace, and finish
+ EndLoc = ConsumeBrace();
+ break;
}
+ AsmToks.push_back(Tok);
+
// Consume the next token; make sure we don't modify the brace count etc.
// if we are in a comment.
EndLoc = TokLoc;
@@ -1703,6 +1723,8 @@
++NumTokensRead;
} while (1);
+ LineEnds.push_back(AsmToks.size());
+
if (InBraces && BraceCount != savedBraceCount) {
// __asm without closing brace (this can happen at EOF).
Diag(Tok, diag::err_expected_rbrace);
@@ -1719,24 +1741,33 @@
break;
EndLoc = ConsumeToken();
} while (1);
- // FIXME: Need to actually grab the data and pass it on to Sema. Ideally,
- // what Sema wants is a string of the entire inline asm, with one instruction
- // per line and all the __asm keywords stripped out, and a way of mapping
- // from any character of that string to its location in the original source
- // code. I'm not entirely sure how to go about that, though.
- Token t;
- t.setKind(tok::string_literal);
- t.setLiteralData("\"/*FIXME: not done*/\"");
- t.clearFlag(Token::NeedsCleaning);
- t.setLength(21);
- ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
- ExprVector Constraints(Actions);
- ExprVector Exprs(Actions);
- ExprVector Clobbers(Actions);
- return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0,
- move_arg(Constraints), move_arg(Exprs),
- AsmString.take(), move_arg(Clobbers),
- EndLoc, true);
+
+ // Collect the tokens into a string
+ SmallString<512> Asm;
+ SmallString<512> TokenBuf;
+ TokenBuf.resize(512);
+ unsigned AsmLineNum = 0;
+ for (unsigned i = 0, e = AsmToks.size(); i < e; i++) {
+ const char *ThisTokBuf = &TokenBuf[0];
+ bool StringInvalid = false;
+ unsigned ThisTokLen =
+ Lexer::getSpelling(AsmToks[i], ThisTokBuf, PP.getSourceManager(),
+ PP.getLangOpts(), &StringInvalid);
+ if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]))
+ Asm += ' '; // FIXME: Too much whitespace around punctuation
+ Asm += StringRef(ThisTokBuf, ThisTokLen);
+ if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) {
+ Asm += '\n';
+ ++AsmLineNum;
+ }
+ }
+
+ // FIXME: We should be passing the tokens and source locations, rather than
+ // (or possibly in addition to the) AsmString. Sema is going to interact with
+ // MC to determine Constraints, Clobbers, etc., which would be simplest to
+ // do with the tokens.
+ std::string AsmString = Asm.data();
+ return Actions.ActOnMSAsmStmt(AsmLoc, AsmString, EndLoc);
}
/// ParseAsmStatement - Parse a GNU extended asm statement.
@@ -1758,18 +1789,6 @@
/// asm-string-literal
/// asm-clobbers ',' asm-string-literal
///
-/// [MS] ms-asm-statement:
-/// ms-asm-block
-/// ms-asm-block ms-asm-statement
-///
-/// [MS] ms-asm-block:
-/// '__asm' ms-asm-line '\n'
-/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
-///
-/// [MS] ms-asm-instruction-block
-/// ms-asm-line
-/// ms-asm-line '\n' ms-asm-instruction-block
-///
StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index cea8a76..7eba772 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -189,6 +189,12 @@
continue;
}
}
+ if (isa<MSAsmStmt>(S)) {
+ // TODO: Verify this is correct.
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
if (isa<CXXTryStmt>(S)) {
HasAbnormalEdge = true;
continue;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 0e39314..fb82890 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2670,6 +2670,15 @@
return Owned(NS);
}
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
+ std::string &AsmString,
+ SourceLocation EndLoc) {
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, AsmString, EndLoc);
+
+ return Owned(NS);
+}
+
StmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, Decl *Parm,
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 01b82aa..08c7d7d 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1179,6 +1179,16 @@
RParenLoc, MSAsm);
}
+ /// \brief Build a new MS style inline asm statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc,
+ std::string &AsmString,
+ SourceLocation EndLoc) {
+ return getSema().ActOnMSAsmStmt(AsmLoc, AsmString, EndLoc);
+ }
+
/// \brief Build a new Objective-C @try statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -5602,6 +5612,14 @@
S->isMSAsm());
}
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
+ // No need to transform the asm string literal.
+ return getDerived().RebuildMSAsmStmt(S->getAsmLoc(),
+ *S->getAsmString(),
+ S->getEndLoc());
+}
template<typename Derived>
StmtResult
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 965b4d1..9823be1 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -317,6 +317,11 @@
Clobbers.data(), NumClobbers);
}
+void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
+ // FIXME: Statement reader not yet implemented for MS style inline asm.
+ VisitStmt(S);
+}
+
void ASTStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
E->setType(Reader.readType(F, Record, Idx));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 9921d6e..1d2efe4 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -249,6 +249,11 @@
Code = serialization::STMT_ASM;
}
+void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
+ // FIXME: Statement writer not yet implemented for MS style inline asm.
+ VisitStmt(S);
+}
+
void ASTStmtWriter::VisitExpr(Expr *E) {
VisitStmt(E);
Writer.AddTypeRef(E->getType(), Record);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 6531265..a95f565 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -670,6 +670,12 @@
Bldr.addNodes(Dst);
break;
+ case Stmt::MSAsmStmtClass:
+ Bldr.takeNodes(Pred);
+ VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
+ break;
+
case Stmt::BlockExprClass:
Bldr.takeNodes(Pred);
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
@@ -1813,6 +1819,12 @@
Bldr.generateNode(A, Pred, state);
}
+void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ Bldr.generateNode(A, Pred, Pred->getState());
+}
+
//===----------------------------------------------------------------------===//
// Visualization.
//===----------------------------------------------------------------------===//