forked from OSchip/llvm-project
Added automatically generated result variables for each
expression. It is now possible to do things like this: (lldb) expr int $i = 5; $i + 1 $0 = (int) 6 (lldb) expr $i + 3 $1 = (int) 8 (lldb) expr $1 + $0 $2 = (int) 14 As a bonus, this allowed us to move printing of expression results into the ClangPersistentVariable class. This code needs a bit of refactoring -- in particular, ClangExpressionDeclMap has eaten one too many bacteria and needs to undergo mitosis -- but the infrastructure appears to be holding up nicely. llvm-svn: 110896
This commit is contained in:
parent
74491bb52c
commit
d1e5b439c9
|
@ -48,7 +48,8 @@ public:
|
|||
const clang::Decl *decl);
|
||||
|
||||
// Interface for IRForTarget
|
||||
bool AddPersistentVariable (const clang::NamedDecl *decl);
|
||||
void GetPersistentResultName (std::string &name);
|
||||
bool AddPersistentVariable (const char *name, TypeFromParser type);
|
||||
bool AddValueToStruct (llvm::Value *value,
|
||||
const clang::NamedDecl *decl,
|
||||
std::string &name,
|
||||
|
@ -84,7 +85,7 @@ public:
|
|||
Error &error);
|
||||
|
||||
bool Dematerialize(ExecutionContext *exe_ctx,
|
||||
lldb_private::Value &result_value,
|
||||
ClangPersistentVariable *&result,
|
||||
Error &error);
|
||||
|
||||
// Interface for ClangASTSource
|
||||
|
@ -127,6 +128,7 @@ private:
|
|||
bool m_struct_laid_out;
|
||||
lldb::addr_t m_allocated_area;
|
||||
lldb::addr_t m_materialized_location;
|
||||
std::string m_result_name;
|
||||
|
||||
Variable *FindVariableInScope(const SymbolContext &sym_ctx,
|
||||
const char *name,
|
||||
|
@ -145,7 +147,7 @@ private:
|
|||
|
||||
bool DoMaterialize (bool dematerialize,
|
||||
ExecutionContext *exe_ctx,
|
||||
lldb_private::Value *result_value, /* must be non-NULL if D is set */
|
||||
ClangPersistentVariable **result, /* must be non-NULL if D is set */
|
||||
Error &err);
|
||||
|
||||
bool DoMaterializeOnePersistentVariable(bool dematerialize,
|
||||
|
|
|
@ -26,12 +26,14 @@ class ClangPersistentVariable
|
|||
friend class ClangPersistentVariables;
|
||||
public:
|
||||
ClangPersistentVariable () :
|
||||
m_name(),
|
||||
m_user_type(),
|
||||
m_data()
|
||||
{
|
||||
}
|
||||
|
||||
ClangPersistentVariable (const ClangPersistentVariable &pv) :
|
||||
m_name(pv.m_name),
|
||||
m_user_type(pv.m_user_type),
|
||||
m_data(pv.m_data)
|
||||
{
|
||||
|
@ -39,6 +41,7 @@ public:
|
|||
|
||||
ClangPersistentVariable &operator=(const ClangPersistentVariable &pv)
|
||||
{
|
||||
m_name = pv.m_name;
|
||||
m_user_type = pv.m_user_type;
|
||||
m_data = pv.m_data;
|
||||
return *this;
|
||||
|
@ -58,12 +61,21 @@ public:
|
|||
{
|
||||
return m_user_type;
|
||||
}
|
||||
|
||||
Error Print(Stream &output_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
lldb::Format format,
|
||||
bool show_types,
|
||||
bool show_summary,
|
||||
bool verbose);
|
||||
private:
|
||||
ClangPersistentVariable (TypeFromUser user_type)
|
||||
ClangPersistentVariable (ConstString name, TypeFromUser user_type)
|
||||
{
|
||||
m_name = name;
|
||||
m_user_type = user_type;
|
||||
m_data = lldb::DataBufferSP(new DataBufferHeap(Size(), 0));
|
||||
}
|
||||
ConstString m_name;
|
||||
TypeFromUser m_user_type;
|
||||
lldb::DataBufferSP m_data;
|
||||
};
|
||||
|
@ -72,9 +84,10 @@ class ClangPersistentVariables
|
|||
{
|
||||
public:
|
||||
ClangPersistentVariable *CreateVariable (ConstString name, TypeFromUser user_type);
|
||||
ClangPersistentVariable *CreateResultVariable (TypeFromUser user_type);
|
||||
ClangPersistentVariable *GetVariable (ConstString name);
|
||||
|
||||
void GetNextResultName(std::string &name);
|
||||
|
||||
ClangPersistentVariables ();
|
||||
private:
|
||||
typedef std::map <ConstString, ClangPersistentVariable> PVarMap;
|
||||
|
|
|
@ -39,6 +39,12 @@ public:
|
|||
llvm::PassManagerType T = llvm::PMT_ModulePassManager);
|
||||
llvm::PassManagerType getPotentialPassManagerType() const;
|
||||
private:
|
||||
// pass to find the result variable created in the result synthesizer and
|
||||
// make a result variable out of it (or a void variable if there is no
|
||||
// result)
|
||||
bool createResultVariable(llvm::Module &M,
|
||||
llvm::Function &F);
|
||||
|
||||
// pass to rewrite Objective-C method calls to use the runtime function
|
||||
// sel_registerName
|
||||
bool RewriteObjCSelector(llvm::Instruction* selector_load,
|
||||
|
|
|
@ -252,7 +252,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
bool canInterpret = false;
|
||||
|
||||
clang::ASTContext *ast_context = clang_expr.GetASTContext ();
|
||||
Value expr_result;
|
||||
ClangPersistentVariable *expr_result = 0;
|
||||
Error expr_error;
|
||||
|
||||
canInterpret = clang_expr.ConvertIRToDWARF (expr_local_vars, dwarf_opcodes);
|
||||
|
@ -373,79 +373,32 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
|
||||
if (!expr_decl_map.Dematerialize(&m_exe_ctx, expr_result, expr_error))
|
||||
{
|
||||
error_stream.Printf ("Couldn't dematerialize struct: %s\n", expr_error.AsCString("unknown error"));
|
||||
error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Interpret the result and print it
|
||||
//
|
||||
|
||||
lldb::Format format = m_options.format;
|
||||
|
||||
// Resolve any values that are possible
|
||||
expr_result.ResolveValue (&m_exe_ctx, ast_context);
|
||||
|
||||
if (expr_result.GetContextType () == Value::eContextTypeInvalid &&
|
||||
expr_result.GetValueType () == Value::eValueTypeScalar &&
|
||||
format == eFormatDefault)
|
||||
if (expr_result)
|
||||
{
|
||||
// The expression result is just a scalar with no special formatting
|
||||
expr_result.GetScalar ().GetValue (&output_stream, m_options.show_types);
|
||||
output_stream.EOL ();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The expression result is more complext and requires special handling
|
||||
DataExtractor data;
|
||||
expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0);
|
||||
|
||||
if (!expr_error.Success ())
|
||||
{
|
||||
error_stream.Printf ("error: couldn't resolve result value: %s\n", expr_error.AsCString ());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format == eFormatDefault)
|
||||
format = expr_result.GetValueDefaultFormat ();
|
||||
|
||||
void *clang_type = expr_result.GetValueOpaqueClangQualType ();
|
||||
|
||||
if (clang_type)
|
||||
{
|
||||
if (m_options.show_types)
|
||||
output_stream.Printf("(%s) ", ClangASTType::GetClangTypeName (clang_type).GetCString());
|
||||
StreamString ss;
|
||||
|
||||
ClangASTType::DumpValue (ast_context, // The ASTContext that the clang type belongs to
|
||||
clang_type, // The opaque clang type we want to dump that value of
|
||||
&m_exe_ctx, // The execution context for memory and variable access
|
||||
&output_stream, // Stream to dump to
|
||||
format, // Format to use when dumping
|
||||
data, // A buffer containing the bytes for the clang type
|
||||
0, // Byte offset within "data" where value is
|
||||
data.GetByteSize (), // Size in bytes of the value we are dumping
|
||||
0, // Bitfield bit size
|
||||
0, // Bitfield bit offset
|
||||
m_options.show_types, // Show types?
|
||||
m_options.show_summary, // Show summary?
|
||||
m_options.debug, // Debug logging output?
|
||||
UINT32_MAX); // Depth to dump in case this is an aggregate type
|
||||
Error err = expr_result->Print (ss,
|
||||
m_exe_ctx,
|
||||
m_options.format,
|
||||
m_options.show_types,
|
||||
m_options.show_summary,
|
||||
m_options.debug);
|
||||
|
||||
if (err.Success())
|
||||
output_stream.PutCString(ss.GetString().c_str());
|
||||
else
|
||||
error_stream.Printf ("Couldn't print result : %s\n", err.AsCString("unknown error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Dump (&output_stream, // Stream to dump to
|
||||
0, // Byte offset within "data"
|
||||
format, // Format to use when dumping
|
||||
data.GetByteSize (), // Size in bytes of each item we are dumping
|
||||
1, // Number of items to dump
|
||||
UINT32_MAX, // Number of items per line
|
||||
LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context
|
||||
0, // Bitfield bit size
|
||||
0); // Bitfield bit offset
|
||||
error_stream.Printf ("Expression produced no result\n");
|
||||
}
|
||||
output_stream.EOL();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,22 +83,25 @@ ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index,
|
|||
|
||||
// Interface for IRForTarget
|
||||
|
||||
void
|
||||
ClangExpressionDeclMap::GetPersistentResultName (std::string &name)
|
||||
{
|
||||
m_persistent_vars->GetNextResultName(m_result_name);
|
||||
|
||||
name = m_result_name;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::AddPersistentVariable (const clang::NamedDecl *decl)
|
||||
ClangExpressionDeclMap::AddPersistentVariable (const char *name, TypeFromParser parser_type)
|
||||
{
|
||||
clang::ASTContext *context(m_exe_ctx->target->GetScratchClangASTContext()->getASTContext());
|
||||
|
||||
const clang::VarDecl *var(dyn_cast<clang::VarDecl>(decl));
|
||||
|
||||
if (!var)
|
||||
return false;
|
||||
|
||||
TypeFromUser user_type(ClangASTContext::CopyType(context,
|
||||
&var->getASTContext(),
|
||||
var->getType().getAsOpaquePtr()),
|
||||
parser_type.GetASTContext(),
|
||||
parser_type.GetOpaqueQualType()),
|
||||
context);
|
||||
|
||||
ConstString const_name(decl->getName().str().c_str());
|
||||
ConstString const_name(name);
|
||||
|
||||
ClangPersistentVariable *pvar = m_persistent_vars->CreateVariable(const_name, user_type);
|
||||
|
||||
|
@ -292,10 +295,10 @@ ClangExpressionDeclMap::Materialize (ExecutionContext *exe_ctx,
|
|||
|
||||
bool
|
||||
ClangExpressionDeclMap::Dematerialize (ExecutionContext *exe_ctx,
|
||||
lldb_private::Value &result_value,
|
||||
ClangPersistentVariable *&result,
|
||||
Error &err)
|
||||
{
|
||||
return DoMaterialize(true, exe_ctx, &result_value, err);
|
||||
return DoMaterialize(true, exe_ctx, &result, err);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -366,11 +369,11 @@ ClangExpressionDeclMap::DumpMaterializedStruct(ExecutionContext *exe_ctx,
|
|||
bool
|
||||
ClangExpressionDeclMap::DoMaterialize (bool dematerialize,
|
||||
ExecutionContext *exe_ctx,
|
||||
lldb_private::Value *result_value,
|
||||
ClangPersistentVariable **result,
|
||||
Error &err)
|
||||
{
|
||||
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
|
||||
|
||||
|
||||
if (!m_struct_laid_out)
|
||||
{
|
||||
err.SetErrorString("Structure hasn't been laid out yet");
|
||||
|
@ -426,36 +429,54 @@ ClangExpressionDeclMap::DoMaterialize (bool dematerialize,
|
|||
|
||||
if (!GetIndexForDecl(tuple_index, iter->m_decl))
|
||||
{
|
||||
if (iter->m_name.find("___clang_expr_result") != std::string::npos)
|
||||
{
|
||||
if (dematerialize)
|
||||
{
|
||||
// Here we pick up the odd anomaly produced by
|
||||
// IRForTarget::createResultVariable (and described in a comment
|
||||
// there).
|
||||
//
|
||||
// We rename the variable to the name of the result PVar and
|
||||
// incidentally drop the address of the PVar into *result
|
||||
// (if it's non-NULL, of course). We then let this case fall
|
||||
// through to the persistent variable handler.
|
||||
|
||||
if (log)
|
||||
log->PutCString("Found result member in the struct");
|
||||
|
||||
iter->m_name = m_result_name;
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("Returning result PVar");
|
||||
|
||||
*result = m_persistent_vars->GetVariable(ConstString(m_result_name.c_str()));
|
||||
|
||||
if (!*result)
|
||||
{
|
||||
err.SetErrorStringWithFormat("Couldn't find persistent variable for result %s", m_result_name.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("Didn't return result PVar; pointer was NULL");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The result variable doesn't need to be materialized, ever.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter->m_name[0] == '$')
|
||||
{
|
||||
if (!DoMaterializeOnePersistentVariable(dematerialize, *exe_ctx, iter->m_name.c_str(), m_materialized_location + iter->m_offset, err))
|
||||
return false;
|
||||
}
|
||||
else if (iter->m_name.find("___clang_expr_result") != std::string::npos)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Found special result variable %s", iter->m_name.c_str());
|
||||
|
||||
if (dematerialize)
|
||||
{
|
||||
clang::ASTContext *context(exe_ctx->target->GetScratchClangASTContext()->getASTContext());
|
||||
|
||||
if (!context)
|
||||
{
|
||||
err.SetErrorString("Couldn't find a scratch AST context to put the result type into");
|
||||
}
|
||||
|
||||
TypeFromUser copied_type(ClangASTContext::CopyType(context,
|
||||
iter->m_parser_type.GetASTContext(),
|
||||
iter->m_parser_type.GetOpaqueQualType()),
|
||||
context);
|
||||
|
||||
result_value->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type.GetOpaqueQualType());
|
||||
|
||||
result_value->SetValueType(Value::eValueTypeLoadAddress);
|
||||
result_value->GetScalar() = (uintptr_t)m_materialized_location + iter->m_offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err.SetErrorStringWithFormat("Unexpected variable %s", iter->m_name.c_str());
|
||||
|
|
|
@ -8,11 +8,98 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangPersistentVariables.h"
|
||||
#include "lldb/Core/DataExtractor.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/Value.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace clang;
|
||||
|
||||
Error
|
||||
ClangPersistentVariable::Print (Stream &output_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
lldb::Format format,
|
||||
bool show_types,
|
||||
bool show_summary,
|
||||
bool verbose)
|
||||
{
|
||||
Error err;
|
||||
|
||||
Value val;
|
||||
|
||||
clang::ASTContext *ast_context = m_user_type.GetASTContext();
|
||||
|
||||
val.SetContext (Value::eContextTypeOpaqueClangQualType, m_user_type.GetOpaqueQualType ());
|
||||
val.SetValueType (Value::eValueTypeHostAddress);
|
||||
val.GetScalar() = (uint64_t)Data ();
|
||||
|
||||
val.ResolveValue (&exe_ctx, ast_context);
|
||||
|
||||
if (val.GetContextType () == Value::eContextTypeInvalid &&
|
||||
val.GetValueType () == Value::eValueTypeScalar &&
|
||||
format == lldb::eFormatDefault)
|
||||
{
|
||||
// The expression result is just a scalar with no special formatting
|
||||
val.GetScalar ().GetValue (&output_stream, show_types);
|
||||
output_stream.EOL ();
|
||||
return err;
|
||||
}
|
||||
|
||||
// The expression result is more complext and requires special handling
|
||||
DataExtractor data;
|
||||
Error expr_error = val.GetValueAsData (&exe_ctx, ast_context, data, 0);
|
||||
|
||||
if (!expr_error.Success ())
|
||||
{
|
||||
err.SetErrorToGenericError ();
|
||||
err.SetErrorStringWithFormat ("Couldn't resolve result value: %s", expr_error.AsCString ());
|
||||
return err;
|
||||
}
|
||||
|
||||
if (format == lldb::eFormatDefault)
|
||||
format = val.GetValueDefaultFormat ();
|
||||
|
||||
void *clang_type = val.GetValueOpaqueClangQualType ();
|
||||
|
||||
output_stream.Printf("%s = ", m_name.AsCString("<anonymous>"));
|
||||
|
||||
if (clang_type)
|
||||
{
|
||||
if (show_types)
|
||||
output_stream.Printf("(%s) ", ClangASTType::GetClangTypeName (clang_type).GetCString());
|
||||
|
||||
ClangASTType::DumpValue (ast_context, // The ASTContext that the clang type belongs to
|
||||
clang_type, // The opaque clang type we want to dump that value of
|
||||
&exe_ctx, // The execution context for memory and variable access
|
||||
&output_stream, // Stream to dump to
|
||||
format, // Format to use when dumping
|
||||
data, // A buffer containing the bytes for the clang type
|
||||
0, // Byte offset within "data" where value is
|
||||
data.GetByteSize (), // Size in bytes of the value we are dumping
|
||||
0, // Bitfield bit size
|
||||
0, // Bitfield bit offset
|
||||
show_types, // Show types?
|
||||
show_summary, // Show summary?
|
||||
verbose, // Debug logging output?
|
||||
UINT32_MAX); // Depth to dump in case this is an aggregate type
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Dump (&output_stream, // Stream to dump to
|
||||
0, // Byte offset within "data"
|
||||
format, // Format to use when dumping
|
||||
data.GetByteSize (), // Size in bytes of each item we are dumping
|
||||
1, // Number of items to dump
|
||||
UINT32_MAX, // Number of items per line
|
||||
LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context
|
||||
0, // Bitfield bit size
|
||||
0); // Bitfield bit offset
|
||||
}
|
||||
|
||||
output_stream.EOL();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
ClangPersistentVariables::ClangPersistentVariables () :
|
||||
m_variables(),
|
||||
|
@ -24,7 +111,7 @@ ClangPersistentVariable *
|
|||
ClangPersistentVariables::CreateVariable (ConstString name,
|
||||
TypeFromUser user_type)
|
||||
{
|
||||
ClangPersistentVariable new_var(user_type);
|
||||
ClangPersistentVariable new_var(name, user_type);
|
||||
|
||||
if (m_variables.find(name) != m_variables.end())
|
||||
return NULL;
|
||||
|
@ -34,21 +121,6 @@ ClangPersistentVariables::CreateVariable (ConstString name,
|
|||
return &m_variables[name];
|
||||
}
|
||||
|
||||
ClangPersistentVariable *
|
||||
ClangPersistentVariables::CreateResultVariable (TypeFromUser user_type)
|
||||
{
|
||||
StreamString s;
|
||||
s.Printf("$%llu", m_result_counter);
|
||||
ConstString name(s.GetString().c_str());
|
||||
|
||||
ClangPersistentVariable *ret = CreateVariable (name, user_type);
|
||||
|
||||
if (ret != NULL)
|
||||
++m_result_counter;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ClangPersistentVariable *
|
||||
ClangPersistentVariables::GetVariable (ConstString name)
|
||||
{
|
||||
|
@ -57,3 +129,14 @@ ClangPersistentVariables::GetVariable (ConstString name)
|
|||
|
||||
return &m_variables[name];
|
||||
}
|
||||
|
||||
void
|
||||
ClangPersistentVariables::GetNextResultName (std::string &name)
|
||||
{
|
||||
StreamString s;
|
||||
s.Printf("$%llu", m_result_counter);
|
||||
|
||||
m_result_counter++;
|
||||
|
||||
name = s.GetString();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/ValueSymbolTable.h"
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
||||
|
@ -55,6 +56,129 @@ IRForTarget::~IRForTarget()
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
IRForTarget::createResultVariable(llvm::Module &M,
|
||||
llvm::Function &F)
|
||||
{
|
||||
lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
|
||||
|
||||
// Find the result variable
|
||||
|
||||
Value *result_value = M.getNamedValue("___clang_expr_result");
|
||||
|
||||
if (!result_value)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("Couldn't find result variable");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log)
|
||||
log->Printf("Found result in the IR: %s", PrintValue(result_value, false).c_str());
|
||||
|
||||
GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value);
|
||||
|
||||
if (!result_global)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("Result variable isn't a GlobalVariable");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the metadata and follow it to the VarDecl
|
||||
|
||||
NamedMDNode *named_metadata = M.getNamedMetadata("clang.global.decl.ptrs");
|
||||
|
||||
if (!named_metadata)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("No global metadata");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned num_nodes = named_metadata->getNumOperands();
|
||||
unsigned node_index;
|
||||
|
||||
MDNode *metadata_node = NULL;
|
||||
|
||||
for (node_index = 0;
|
||||
node_index < num_nodes;
|
||||
++node_index)
|
||||
{
|
||||
metadata_node = named_metadata->getOperand(node_index);
|
||||
|
||||
if (metadata_node->getNumOperands() != 2)
|
||||
continue;
|
||||
|
||||
if (metadata_node->getOperand(0) == result_global)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!metadata_node)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("Couldn't find result metadata");
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstantInt *constant_int = dyn_cast<ConstantInt>(metadata_node->getOperand(1));
|
||||
|
||||
uint64_t result_decl_intptr = constant_int->getZExtValue();
|
||||
|
||||
clang::VarDecl *result_decl = reinterpret_cast<clang::VarDecl *>(result_decl_intptr);
|
||||
|
||||
// Get the next available result name from m_decl_map and create the persistent
|
||||
// variable for it
|
||||
|
||||
lldb_private::TypeFromParser result_decl_type (result_decl->getType().getAsOpaquePtr(),
|
||||
&result_decl->getASTContext());
|
||||
std::string new_result_name;
|
||||
|
||||
m_decl_map->GetPersistentResultName(new_result_name);
|
||||
m_decl_map->AddPersistentVariable(new_result_name.c_str(), result_decl_type);
|
||||
|
||||
if (log)
|
||||
log->Printf("Creating a new result global: %s", new_result_name.c_str());
|
||||
|
||||
// Construct a new result global and set up its metadata
|
||||
|
||||
GlobalVariable *new_result_global = new GlobalVariable(M,
|
||||
result_global->getType()->getElementType(),
|
||||
false, /* not constant */
|
||||
GlobalValue::ExternalLinkage,
|
||||
NULL, /* no initializer */
|
||||
new_result_name.c_str());
|
||||
|
||||
// It's too late in compilation to create a new VarDecl for this, but we don't
|
||||
// need to. We point the metadata at the old VarDecl. This creates an odd
|
||||
// anomaly: a variable with a Value whose name is something like $0 and a
|
||||
// Decl whose name is ___clang_expr_result. This condition is handled in
|
||||
// ClangExpressionDeclMap::DoMaterialize, and the name of the variable is
|
||||
// fixed up.
|
||||
|
||||
ConstantInt *new_constant_int = ConstantInt::get(constant_int->getType(),
|
||||
result_decl_intptr,
|
||||
false);
|
||||
|
||||
llvm::Value* values[2];
|
||||
values[0] = new_result_global;
|
||||
values[1] = new_constant_int;
|
||||
|
||||
MDNode *persistent_global_md = MDNode::get(M.getContext(), values, 2);
|
||||
named_metadata->addOperand(persistent_global_md);
|
||||
|
||||
if (log)
|
||||
log->Printf("Replacing %s with %s",
|
||||
PrintValue(result_global).c_str(),
|
||||
PrintValue(new_result_global).c_str());
|
||||
|
||||
result_global->replaceAllUsesWith(new_result_global);
|
||||
result_global->eraseFromParent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isObjCSelectorRef(Value *V)
|
||||
{
|
||||
GlobalVariable *GV = dyn_cast<GlobalVariable>(V);
|
||||
|
@ -234,9 +358,12 @@ IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc,
|
|||
|
||||
uintptr_t ptr = constant_int->getZExtValue();
|
||||
|
||||
clang::NamedDecl *decl = reinterpret_cast<clang::NamedDecl *>(ptr);
|
||||
clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr);
|
||||
|
||||
if (!m_decl_map->AddPersistentVariable(decl))
|
||||
lldb_private::TypeFromParser result_decl_type (decl->getType().getAsOpaquePtr(),
|
||||
&decl->getASTContext());
|
||||
|
||||
if (!m_decl_map->AddPersistentVariable(decl->getName().str().c_str(), result_decl_type))
|
||||
return false;
|
||||
|
||||
GlobalVariable *persistent_global = new GlobalVariable(M,
|
||||
|
@ -760,7 +887,7 @@ IRForTarget::replaceVariables(Module &M, Function &F)
|
|||
|
||||
if (log)
|
||||
log->Printf(" %s (%s) placed at %d",
|
||||
decl->getIdentifier()->getNameStart(),
|
||||
value->getName().str().c_str(),
|
||||
PrintValue(value, true).c_str(),
|
||||
offset);
|
||||
|
||||
|
@ -797,6 +924,13 @@ IRForTarget::runOnModule(Module &M)
|
|||
|
||||
Function::iterator bbi;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Replace __clang_expr_result with a persistent variable
|
||||
//
|
||||
|
||||
if (!createResultVariable(M, *function))
|
||||
return false;
|
||||
|
||||
//////////////////////////////////
|
||||
// Run basic-block level passes
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue