Hitherto the IRForTarget infrastructure has mainly

been suitable for preparing a single IR function
for operation in the target.  However, using blocks
and lambdas creates other IR functions that also
need to be processed.

I have audited IRForTarget to make it process
multiple functions.  Where IRForTarget would add
new instructions at the beginning of the main
expression function, it now adds them on-demand
in the function where they are needed.  This is
enabled by a system of FunctionValueCaches, which
invoke a lambda to create or derive the values as
needed, or report the result of that lambda if it
has already been called for the given function.

<rdar://problem/14180236>

llvm-svn: 185224
This commit is contained in:
Sean Callanan 2013-06-28 21:44:15 +00:00
parent e9672d0448
commit 1f9db3ebe3
2 changed files with 285 additions and 205 deletions

View File

@ -18,6 +18,8 @@
#include "lldb/Symbol/TaggedASTType.h"
#include "llvm/Pass.h"
#include <map>
namespace llvm {
class BasicBlock;
class CallInst;
@ -235,8 +237,7 @@ private:
/// be determined); false otherwise.
//------------------------------------------------------------------
bool
ResolveFunctionPointers (llvm::Module &llvm_module,
llvm::Function &llvm_function);
ResolveFunctionPointers (llvm::Module &llvm_module);
//------------------------------------------------------------------
/// A function-level pass to take the generated global value
@ -307,7 +308,7 @@ private:
CreateResultVariable (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A function-level pass to find Objective-C constant strings and
/// A module-level pass to find Objective-C constant strings and
/// transform them to calls to CFStringCreateWithBytes.
//------------------------------------------------------------------
@ -321,32 +322,21 @@ private:
/// The constant C string inside the NSString. This will be
/// passed as the bytes argument to CFStringCreateWithBytes.
///
/// @param[in] FirstEntryInstruction
/// An instruction early in the execution of the function.
/// When this function synthesizes a call to
/// CFStringCreateWithBytes, it places the call before this
/// instruction. The instruction should come before all
/// uses of the NSString.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCConstString (llvm::GlobalVariable *NSStr,
llvm::GlobalVariable *CStr,
llvm::Instruction *FirstEntryInstruction);
llvm::GlobalVariable *CStr);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_function
/// The function currently being processed.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCConstStrings (llvm::Function &llvm_function);
RewriteObjCConstStrings ();
//------------------------------------------------------------------
/// A basic block-level pass to find all Objective-C method calls and
@ -686,10 +676,26 @@ private:
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
class FunctionValueCache {
public:
typedef std::function <llvm::Value *(llvm::Function *)> Maker;
FunctionValueCache (Maker const &maker);
~FunctionValueCache ();
llvm::Value *GetValue (llvm::Function *function);
private:
Maker const m_maker;
typedef std::map<llvm::Function *, llvm::Value *> FunctionValueMap;
FunctionValueMap m_values;
};
FunctionValueCache m_entry_instruction_finder;
static bool
UnfoldConstant (llvm::Constant *old_constant,
llvm::Value *new_constant,
llvm::Instruction *first_entry_inst);
FunctionValueCache &value_maker,
FunctionValueCache &entry_instruction_finder);
//------------------------------------------------------------------
/// Construct a reference to m_reloc_placeholder with a given type

View File

@ -47,6 +47,27 @@ IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionU
{
}
IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) :
m_maker(maker),
m_values()
{
}
IRForTarget::FunctionValueCache::~FunctionValueCache()
{
}
llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
{
if (!m_values.count(function))
{
llvm::Value *ret = m_maker(function);
m_values[function] = ret;
return ret;
}
return m_values[function];
}
lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
{
lldb_private::Error err;
@ -62,6 +83,14 @@ lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
return m_allocation;
}
static llvm::Value *FindEntryInstruction (llvm::Function *function)
{
if (function->empty())
return NULL;
return function->getEntryBlock().getFirstNonPHIOrDbg();
}
IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
bool resolve_vars,
lldb_private::IRExecutionUnit &execution_unit,
@ -78,7 +107,8 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
m_error_stream(error_stream),
m_result_store(NULL),
m_result_is_pointer(false),
m_reloc_placeholder(NULL)
m_reloc_placeholder(NULL),
m_entry_instruction_finder (FindEntryInstruction)
{
}
@ -288,8 +318,7 @@ IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
}
bool
IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module,
llvm::Function &llvm_function)
IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -675,8 +704,7 @@ static void DebugUsers(Log *log, Value *value, uint8_t depth)
bool
IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
llvm::GlobalVariable *cstr,
Instruction *FirstEntryInstruction)
llvm::GlobalVariable *cstr)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -767,12 +795,14 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
ArrayRef <Value *> CFSCWB_arguments(argument_array, 5);
CallInst *CFSCWB_call = CallInst::Create(m_CFStringCreateWithBytes,
FunctionValueCache CFSCWB_Caller ([this, &CFSCWB_arguments] (llvm::Function *function)->llvm::Value * {
return CallInst::Create(m_CFStringCreateWithBytes,
CFSCWB_arguments,
"CFStringCreateWithBytes",
FirstEntryInstruction);
llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function)));
});
if (!UnfoldConstant(ns_str, CFSCWB_call, FirstEntryInstruction))
if (!UnfoldConstant(ns_str, CFSCWB_Caller, m_entry_instruction_finder))
{
if (log)
log->PutCString("Couldn't replace the NSString with the result of the call");
@ -789,26 +819,12 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
}
bool
IRForTarget::RewriteObjCConstStrings(Function &llvm_function)
IRForTarget::RewriteObjCConstStrings()
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
BasicBlock &entry_block(llvm_function.getEntryBlock());
Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
if (!FirstEntryInstruction)
{
if (log)
log->PutCString("Couldn't find first instruction for rewritten Objective-C strings");
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find the location for calls to CFStringCreateWithBytes\n");
return false;
}
for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
vi != ve;
++vi)
@ -977,7 +993,7 @@ IRForTarget::RewriteObjCConstStrings(Function &llvm_function)
if (!cstr_array)
cstr_global = NULL;
if (!RewriteObjCConstString(nsstring_global, cstr_global, FirstEntryInstruction))
if (!RewriteObjCConstString(nsstring_global, cstr_global))
{
if (log)
log->PutCString("Error rewriting the constant string");
@ -2151,7 +2167,9 @@ IRForTarget::RemoveGuards(BasicBlock &basic_block)
// This function does not report errors; its callers are responsible.
bool
IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruction *first_entry_inst)
IRForTarget::UnfoldConstant(Constant *old_constant,
FunctionValueCache &value_maker,
FunctionValueCache &entry_instruction_finder)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -2186,17 +2204,20 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
return false;
case Instruction::BitCast:
{
FunctionValueCache bit_cast_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
// UnaryExpr
// OperandList[0] is value
Value *s = constant_expr->getOperand(0);
if (constant_expr->getOperand(0) != old_constant)
return constant_expr;
if (s == old_constant)
s = new_constant;
return new BitCastInst(value_maker.GetValue(function),
constant_expr->getType(),
"",
llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
BitCastInst *bit_cast(new BitCastInst(s, constant_expr->getType(), "", first_entry_inst));
UnfoldConstant(constant_expr, bit_cast, first_entry_inst);
return UnfoldConstant(constant_expr, bit_cast_maker, entry_instruction_finder);
}
break;
case Instruction::GetElementPtr:
@ -2205,10 +2226,11 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
// OperandList[0] is base
// OperandList[1]... are indices
FunctionValueCache get_element_pointer_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
Value *ptr = constant_expr->getOperand(0);
if (ptr == old_constant)
ptr = new_constant;
ptr = value_maker.GetValue(function);
std::vector<Value*> index_vector;
@ -2222,16 +2244,17 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
Value *operand = constant_expr->getOperand(operand_index);
if (operand == old_constant)
operand = new_constant;
operand = value_maker.GetValue(function);
index_vector.push_back(operand);
}
ArrayRef <Value*> indices(index_vector);
GetElementPtrInst *get_element_ptr(GetElementPtrInst::Create(ptr, indices, "", first_entry_inst));
return GetElementPtrInst::Create(ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
UnfoldConstant(constant_expr, get_element_ptr, first_entry_inst);
return UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder);
}
break;
}
@ -2245,8 +2268,16 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
}
else
{
// simple fall-through case for non-constants
user->replaceUsesOfWith(old_constant, new_constant);
if (Instruction *inst = llvm::dyn_cast<Instruction>(user))
{
inst->replaceUsesOfWith(old_constant, value_maker.GetValue(inst->getParent()->getParent()));
}
else
{
if (log)
log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(user).c_str());
return false;
}
}
}
@ -2388,38 +2419,57 @@ IRForTarget::ReplaceVariables (Function &llvm_function)
decl->getNameAsString().c_str(),
offset);
ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument, offset_int, "", FirstEntryInstruction);
if (value)
{
Value *replacement = NULL;
if (log)
log->Printf(" Replacing [%s]", PrintValue(value).c_str());
FunctionValueCache body_result_maker ([this, name, offset_type, offset, argument, value] (llvm::Function *function)->llvm::Value * {
// Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in cases where the result
// variable is an rvalue, we have to synthesize a dereference of the appropriate structure
// entry in order to produce the static variable that the AST thinks it is accessing.
llvm::Instruction *entry_instruction = llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function));
ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument,
offset_int,
"",
entry_instruction);
if (name == m_result_name && !m_result_is_pointer)
{
BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType()->getPointerTo(), "", FirstEntryInstruction);
BitCastInst *bit_cast = new BitCastInst(get_element_ptr,
value->getType()->getPointerTo(),
"",
entry_instruction);
LoadInst *load = new LoadInst(bit_cast, "", FirstEntryInstruction);
LoadInst *load = new LoadInst(bit_cast, "", entry_instruction);
replacement = load;
return load;
}
else
{
BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", FirstEntryInstruction);
BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", entry_instruction);
replacement = bit_cast;
return bit_cast;
}
});
if (Constant *constant = dyn_cast<Constant>(value))
UnfoldConstant(constant, replacement, FirstEntryInstruction);
{
UnfoldConstant(constant, body_result_maker, m_entry_instruction_finder);
}
else if (Instruction *instruction = dyn_cast<Instruction>(value))
{
value->replaceAllUsesWith(body_result_maker.GetValue(instruction->getParent()->getParent()));
}
else
value->replaceAllUsesWith(replacement);
{
if (log)
log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(value).c_str());
return false;
}
if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
var->eraseFromParent();
@ -2544,27 +2594,6 @@ IRForTarget::runOnModule (Module &llvm_module)
m_module = &llvm_module;
m_target_data.reset(new DataLayout(m_module));
Function* function = m_module->getFunction(StringRef(m_func_name.c_str()));
if (!function)
{
if (log)
log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
return false;
}
if (!FixFunctionLinkage (*function))
{
if (log)
log->Printf("Couldn't fix the linkage for the function");
return false;
}
if (log)
{
std::string s;
@ -2577,6 +2606,27 @@ IRForTarget::runOnModule (Module &llvm_module)
log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str());
}
Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str()));
if (!main_function)
{
if (log)
log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
return false;
}
if (!FixFunctionLinkage (*main_function))
{
if (log)
log->Printf("Couldn't fix the linkage for the function");
return false;
}
llvm::Type *intptr_ty = Type::getInt8Ty(m_module->getContext());
m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
@ -2589,13 +2639,11 @@ IRForTarget::runOnModule (Module &llvm_module)
GlobalVariable::NotThreadLocal /* ThreadLocal */,
0 /* AddressSpace */);
Function::iterator bbi;
////////////////////////////////////////////////////////////
// Replace $__lldb_expr_result with a persistent variable
//
if (!CreateResultVariable(*function))
if (!CreateResultVariable(*main_function))
{
if (log)
log->Printf("CreateResultVariable() failed");
@ -2605,6 +2653,29 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream oss(s);
m_module->print(oss, NULL);
oss.flush();
log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
}
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
{
llvm::Function *function = fi;
if (function->begin() == function->end())
continue;
Function::iterator bbi;
for (bbi = function->begin();
bbi != function->end();
++bbi)
@ -2639,24 +2710,13 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
}
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream oss(s);
m_module->print(oss, NULL);
oss.flush();
log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
}
///////////////////////////////////////////////////////////////////////////////
// Fix all Objective-C constant strings to use NSStringWithCString:encoding:
//
if (!RewriteObjCConstStrings(*function))
if (!RewriteObjCConstStrings())
{
if (log)
log->Printf("RewriteObjCConstStrings() failed");
@ -2670,7 +2730,7 @@ IRForTarget::runOnModule (Module &llvm_module)
// Resolve function pointers
//
if (!ResolveFunctionPointers(llvm_module, *function))
if (!ResolveFunctionPointers(llvm_module))
{
if (log)
log->Printf("ResolveFunctionPointers() failed");
@ -2680,8 +2740,14 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
for (bbi = function->begin();
bbi != function->end();
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
{
llvm::Function *function = fi;
for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
bbi != bbe;
++bbi)
{
if (!RewriteObjCSelectors(*bbi))
@ -2694,9 +2760,16 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
}
}
for (bbi = function->begin();
bbi != function->end();
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
{
llvm::Function *function = fi;
for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
bbi != bbe;
++bbi)
{
if (!ResolveCalls(*bbi))
@ -2717,12 +2790,13 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
}
}
///////////////////////////////
// Run function-level passes
////////////////////////////////////////////////////////////////////////
// Run function-level passes that only make sense on the main function
//
if (!ResolveExternals(*function))
if (!ResolveExternals(*main_function))
{
if (log)
log->Printf("ResolveExternals() failed");
@ -2732,7 +2806,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceVariables(*function))
if (!ReplaceVariables(*main_function))
{
if (log)
log->Printf("ReplaceVariables() failed");