Added a SemaConsumer that transforms the ASTs for

an expression, adding code to put the value of the
last expression (if there is one) into a variable
and write the address of that variable to a global
pointer.

llvm-svn: 107419
This commit is contained in:
Sean Callanan
2010-07-01 20:08:22 +00:00
parent 329d202362
commit 116be5347e
6 changed files with 460 additions and 40 deletions

View File

@@ -49,11 +49,15 @@ public:
unsigned Compile();
unsigned
ParseExpression (const char *expr_text, Stream &stream);
ParseExpression (const char *expr_text,
Stream &stream,
bool add_result_var = false);
unsigned
ParseBareExpression (llvm::StringRef expr_text, Stream &stream);
ParseBareExpression (llvm::StringRef expr_text,
Stream &stream,
bool add_result_var = false);
unsigned
ConvertExpressionToDWARF (ClangExpressionVariableList &expr_local_variable_list,
StreamString &dwarf_opcode_strm);

View File

@@ -0,0 +1,51 @@
//===-- ClangResultSynthesizer.h --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ClangResultSynthesizer_h_
#define liblldb_ClangResultSynthesizer_h_
#include "clang/Sema/SemaConsumer.h"
namespace clang {
class Action;
}
namespace lldb_private {
class ClangResultSynthesizer : public clang::SemaConsumer
{
public:
ClangResultSynthesizer(clang::ASTConsumer *passthrough);
~ClangResultSynthesizer();
void Initialize(clang::ASTContext &Context);
void HandleTopLevelDecl(clang::DeclGroupRef D);
void HandleTranslationUnit(clang::ASTContext &Ctx);
void HandleTagDeclDefinition(clang::TagDecl *D);
void CompleteTentativeDefinition(clang::VarDecl *D);
void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired);
void PrintStats();
void InitializeSema(clang::Sema &S);
void ForgetSema();
private:
void TransformTopLevelDecl(clang::Decl *D);
bool SynthesizeResult(clang::ASTContext &Ctx,
clang::FunctionDecl *FunDecl);
clang::ASTContext *m_ast_context;
clang::ASTConsumer *m_passthrough;
clang::SemaConsumer *m_passthrough_sema;
clang::Sema *m_sema;
clang::Action *m_action;
};
}
#endif

View File

@@ -328,6 +328,8 @@
26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */; };
26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
49A8A3A011D568A300AD3B68 /* ClangResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */; };
49A8A3A411D568BF00AD3B68 /* ClangResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */; };
49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D7072611B5AD03001AD875 /* ClangASTSource.h */; };
49D7072911B5AD11001AD875 /* ClangASTSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */; settings = {COMPILER_FLAGS = "-fno-rtti"; }; };
49F1A74611B3388F003ED505 /* ClangExpressionDeclMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */; };
@@ -896,6 +898,8 @@
497E7B9D1188F6690065CCA1 /* ABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABI.cpp; path = source/Target/ABI.cpp; sourceTree = "<group>"; };
499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectArgs.h; path = source/Commands/CommandObjectArgs.h; sourceTree = "<group>"; };
499F381F11A5B3F300F5CE02 /* CommandObjectArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectArgs.cpp; path = source/Commands/CommandObjectArgs.cpp; sourceTree = "<group>"; };
49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangResultSynthesizer.cpp; path = source/Expression/ClangResultSynthesizer.cpp; sourceTree = "<group>"; };
49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangResultSynthesizer.h; path = include/lldb/Expression/ClangResultSynthesizer.h; sourceTree = "<group>"; };
49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCObjectPrinter.cpp; path = source/Target/ObjCObjectPrinter.cpp; sourceTree = "<group>"; };
49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCObjectPrinter.h; path = include/lldb/Target/ObjCObjectPrinter.h; sourceTree = "<group>"; };
49D7072611B5AD03001AD875 /* ClangASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTSource.h; path = include/lldb/Expression/ClangASTSource.h; sourceTree = "<group>"; };
@@ -1822,6 +1826,8 @@
49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */,
26BC7DC110F1B79500F91463 /* ClangExpressionVariable.h */,
26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */,
49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */,
49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */,
26BC7DC210F1B79500F91463 /* ClangStmtVisitor.h */,
26BC7ED710F1B86700F91463 /* ClangStmtVisitor.cpp */,
26BC7DC310F1B79500F91463 /* DWARFExpression.h */,
@@ -2177,6 +2183,7 @@
49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */,
261B5A5511C3F2AD00AABD0A /* SharingPtr.h in Headers */,
4C08CDEC11C81F1E001610A8 /* ThreadSpec.h in Headers */,
49A8A3A411D568BF00AD3B68 /* ClangResultSynthesizer.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2625,6 +2632,7 @@
AF94005911C03F6500085DB9 /* SymbolVendor.cpp in Sources */,
261B5A5411C3F2AD00AABD0A /* SharingPtr.cpp in Sources */,
4C08CDE811C81EF8001610A8 /* ThreadSpec.cpp in Sources */,
49A8A3A011D568A300AD3B68 /* ClangResultSynthesizer.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -233,7 +233,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
if (bare)
num_errors = clang_expr.ParseBareExpression (llvm::StringRef (expr), error_stream);
else
num_errors = clang_expr.ParseExpression (expr, error_stream);
num_errors = clang_expr.ParseExpression (expr, error_stream, m_options.use_ir);
if (num_errors)
{

View File

@@ -38,6 +38,7 @@
#include "clang/Frontend/VerifyDiagnosticsClient.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/ParseAST.h"
#include "clang/Sema/SemaConsumer.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Module.h"
@@ -53,6 +54,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangResultSynthesizer.h"
#include "lldb/Expression/ClangStmtVisitor.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Expression/RecordingMemoryManager.h"
@@ -279,19 +281,23 @@ ClangExpression::GetASTContext ()
}
unsigned
ClangExpression::ParseExpression (const char *expr_text, Stream &stream)
ClangExpression::ParseExpression (const char *expr_text,
Stream &stream,
bool add_result_var)
{
// HACK: for now we have to make a function body around our expression
// since there is no way to parse a single expression line in LLVM/Clang.
std::string func_expr("void ___clang_expr()\n{\n\t");
std::string func_expr("extern \"C\" void ___clang_expr()\n{\n\t");
func_expr.append(expr_text);
func_expr.append(";\n}");
return ParseBareExpression (func_expr, stream);
return ParseBareExpression (func_expr, stream, add_result_var);
}
unsigned
ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream)
ClangExpression::ParseBareExpression (llvm::StringRef expr_text,
Stream &stream,
bool add_result_var)
{
Mutex::Locker locker(GetClangMutex ());
@@ -354,7 +360,17 @@ ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream)
// - CodeGeneration ASTConsumer (include/clang/ModuleBuilder.h), which will be passed in when you call...
// - Call clang::ParseAST (in lib/Sema/ParseAST.cpp) to parse the buffer. The CodeGenerator will generate code for __dbg_expr.
// - Once ParseAST completes, you can grab the llvm::Module from the CodeGenerator, which will have an llvm::Function you can hand off to the JIT.
ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext());
if (add_result_var)
{
ClangResultSynthesizer result_synthesizer(m_code_generator_ptr);
ParseAST(m_clang_ap->getPreprocessor(), &result_synthesizer, m_clang_ap->getASTContext());
}
else
{
ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext());
}
text_diagnostic_buffer.EndSourceFile();
@@ -413,7 +429,6 @@ ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream)
return num_errors;
}
static FrontendAction *
CreateFrontendAction(CompilerInstance &CI)
{
@@ -471,41 +486,42 @@ ClangExpression::ConvertIRToDWARF (ClangExpressionVariableList &excpr_local_vari
return 1;
}
llvm::Module::iterator fi;
for (fi = module->begin();
fi != module->end();
++fi)
llvm::Function* function = module->getFunction(StringRef("___clang_expr"));
if (!function)
{
llvm::Function &function = *fi;
if (log)
log->Printf("IR for %s:", function.getName().str().c_str());
log->Printf("Couldn't find ___clang_expr() in the module");
return 1;
}
if (log)
log->Printf("IR for %s:", function->getName().str().c_str());
llvm::Function::iterator bbi;
for (bbi = function->begin();
bbi != function->end();
++bbi)
{
llvm::BasicBlock &bb = *bbi;
llvm::Function::iterator bbi;
llvm::BasicBlock::iterator ii;
for (bbi = function.begin();
bbi != function.end();
++bbi)
for (ii = bb.begin();
ii != bb.end();
++ii)
{
llvm::BasicBlock &bb = *bbi;
llvm::BasicBlock::iterator ii;
for (ii = bb.begin();
ii != bb.end();
++ii)
{
llvm::Instruction &inst = *ii;
std::string s;
llvm::raw_string_ostream os(s);
inst.print(os);
if (log)
log->Printf(" %s", s.c_str());
}
llvm::Instruction &inst = *ii;
std::string s;
llvm::raw_string_ostream os(s);
inst.print(os);
if (log)
log->Printf(" %s", s.c_str());
}
}

View File

@@ -0,0 +1,341 @@
//===-- ClangResultSynthesizer.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "stdlib.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Action.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/Scope.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "lldb/Core/Log.h"
#include "lldb/Expression/ClangResultSynthesizer.h"
using namespace llvm;
using namespace clang;
using namespace lldb_private;
ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) :
m_passthrough(passthrough),
m_passthrough_sema(NULL),
m_sema(NULL),
m_ast_context(NULL)
{
if (!m_passthrough)
return;
m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
}
ClangResultSynthesizer::~ClangResultSynthesizer()
{
}
void
ClangResultSynthesizer::Initialize(ASTContext &Context)
{
m_ast_context = &Context;
if (m_passthrough)
m_passthrough->Initialize(Context);
}
void
ClangResultSynthesizer::TransformTopLevelDecl(Decl* D)
{
LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
if (linkage_spec_decl)
{
RecordDecl::decl_iterator decl_iterator;
for (decl_iterator = linkage_spec_decl->decls_begin();
decl_iterator != linkage_spec_decl->decls_end();
++decl_iterator)
{
TransformTopLevelDecl(*decl_iterator);
}
}
FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
if (m_ast_context &&
function_decl &&
!strcmp(function_decl->getNameAsCString(),
"___clang_expr"))
{
SynthesizeResult(*m_ast_context, function_decl);
}
}
void
ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
{
DeclGroupRef::iterator decl_iterator;
for (decl_iterator = D.begin();
decl_iterator != D.end();
++decl_iterator)
{
Decl *decl = *decl_iterator;
TransformTopLevelDecl(decl);
}
if (m_passthrough)
m_passthrough->HandleTopLevelDecl(D);
}
bool
ClangResultSynthesizer::SynthesizeResult (ASTContext &Ctx,
FunctionDecl *FunDecl)
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
if (!m_sema)
return false;
FunctionDecl *function_decl = FunDecl;
if (!function_decl)
return false;
Stmt *function_body = function_decl->getBody();
CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
if (!compound_stmt)
return false;
if (compound_stmt->body_empty())
return false;
Stmt **last_stmt_ptr = compound_stmt->body_end() - 1;
Stmt *last_stmt = *last_stmt_ptr;
Expr *last_expr = dyn_cast<Expr>(last_stmt);
if (!last_expr)
// No auxiliary variable necessary; expression returns void
return true;
QualType expr_qual_type = last_expr->getType();
clang::Type *expr_type = expr_qual_type.getTypePtr();
if (!expr_type)
return false;
if (expr_type->isVoidType())
return true;
if (log)
{
std::string s = expr_qual_type.getAsString();
log->Printf("Last statement's type: %s", s.c_str());
}
IdentifierInfo &result_id = Ctx.Idents.get("___clang_expr_result");
DeclContext *decl_context = function_decl->getDeclContext();
clang::VarDecl *result_decl = VarDecl::Create(Ctx,
function_decl,
SourceLocation(),
&result_id,
expr_qual_type,
NULL,
VarDecl::Static,
VarDecl::Static);
if (!result_decl)
return false;
function_decl->addDecl(result_decl);
///////////////////////////////
// call AddInitializerToDecl
//
Parser::DeclPtrTy result_decl_ptr;
result_decl_ptr.set(result_decl);
m_action->AddInitializerToDecl(result_decl_ptr, Parser::ExprArg(*m_action, last_expr));
/////////////////////////////////
// call ConvertDeclToDeclGroup
//
Parser::DeclGroupPtrTy result_decl_group_ptr;
result_decl_group_ptr = m_action->ConvertDeclToDeclGroup(result_decl_ptr);
////////////////////////
// call ActOnDeclStmt
//
Parser::OwningStmtResult result_initialization_stmt_result(m_action->ActOnDeclStmt(result_decl_group_ptr,
SourceLocation(),
SourceLocation()));
///////////////////////////////////////////////
// Synthesize external void pointer variable
//
IdentifierInfo &result_ptr_id = Ctx.Idents.get("___clang_expr_result_ptr");
clang::VarDecl *result_ptr_decl = VarDecl::Create(Ctx,
decl_context,
SourceLocation(),
&result_ptr_id,
Ctx.VoidPtrTy,
NULL,
VarDecl::Extern,
VarDecl::Extern);
/////////////////////////////////////////////
// Build a DeclRef for the result variable
//
DeclRefExpr *result_decl_ref_expr = DeclRefExpr::Create(Ctx,
NULL,
SourceRange(),
result_decl,
SourceLocation(),
expr_qual_type);
///////////////////////
// call ActOnUnaryOp
//
Scope my_scope(NULL, (Scope::BlockScope | Scope::FnScope | Scope::DeclScope));
Parser::DeclPtrTy result_ptr_decl_ptr;
result_ptr_decl_ptr.set(result_ptr_decl);
Parser::OwningExprResult addressof_expr_result(m_action->ActOnUnaryOp(&my_scope,
SourceLocation(),
tok::amp,
Parser::ExprArg(*m_action, result_decl_ref_expr)));
////////////////////////////////////////////
// Build a DeclRef for the result pointer
//
DeclRefExpr *result_ptr_decl_ref_expr = DeclRefExpr::Create(Ctx,
NULL,
SourceRange(),
result_ptr_decl,
SourceLocation(),
Ctx.VoidPtrTy);
////////////////////////
// call ActOnBinaryOp
//
Parser::OwningExprResult assignment_expr_result(m_action->ActOnBinOp(&my_scope,
SourceLocation(),
tok::equal,
Parser::ExprArg(*m_action, result_ptr_decl_ref_expr),
Parser::ExprArg(*m_action, addressof_expr_result.take())));
////////////////////////////
// call ActOnCompoundStmt
//
void *stmts[2];
stmts[0] = result_initialization_stmt_result.take();
stmts[1] = assignment_expr_result.take();
Parser::OwningStmtResult compound_stmt_result(m_action->ActOnCompoundStmt(SourceLocation(),
SourceLocation(),
Parser::MultiStmtArg(*m_action, stmts, 2),
false));
////////////////////////////////////////////////
// replace the old statement with the new one
//
*last_stmt_ptr = reinterpret_cast<Stmt*>(compound_stmt_result.take());
if (log)
{
std::string s;
raw_string_ostream os(s);
function_decl->print(os);
os.flush();
log->Printf("Transformed function AST:\n%s", s.c_str());
}
return true;
}
void
ClangResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
{
if (m_passthrough)
m_passthrough->HandleTranslationUnit(Ctx);
}
void
ClangResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
{
if (m_passthrough)
m_passthrough->HandleTagDeclDefinition(D);
}
void
ClangResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
{
if (m_passthrough)
m_passthrough->CompleteTentativeDefinition(D);
}
void
ClangResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
{
if (m_passthrough)
m_passthrough->HandleVTable(RD, DefinitionRequired);
}
void
ClangResultSynthesizer::PrintStats()
{
if (m_passthrough)
m_passthrough->PrintStats();
}
void
ClangResultSynthesizer::InitializeSema(Sema &S)
{
m_sema = &S;
m_action = reinterpret_cast<Action*>(m_sema);
if (m_passthrough_sema)
m_passthrough_sema->InitializeSema(S);
}
void
ClangResultSynthesizer::ForgetSema()
{
m_sema = NULL;
m_action = NULL;
if (m_passthrough_sema)
m_passthrough_sema->ForgetSema();
}