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 "lldb/Symbol/TaggedASTType.h"
#include "llvm/Pass.h" #include "llvm/Pass.h"
#include <map>
namespace llvm { namespace llvm {
class BasicBlock; class BasicBlock;
class CallInst; class CallInst;
@ -235,8 +237,7 @@ private:
/// be determined); false otherwise. /// be determined); false otherwise.
//------------------------------------------------------------------ //------------------------------------------------------------------
bool bool
ResolveFunctionPointers (llvm::Module &llvm_module, ResolveFunctionPointers (llvm::Module &llvm_module);
llvm::Function &llvm_function);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// A function-level pass to take the generated global value /// A function-level pass to take the generated global value
@ -307,7 +308,7 @@ private:
CreateResultVariable (llvm::Function &llvm_function); 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. /// transform them to calls to CFStringCreateWithBytes.
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -321,32 +322,21 @@ private:
/// The constant C string inside the NSString. This will be /// The constant C string inside the NSString. This will be
/// passed as the bytes argument to CFStringCreateWithBytes. /// 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 /// @return
/// True on success; false otherwise /// True on success; false otherwise
//------------------------------------------------------------------ //------------------------------------------------------------------
bool bool
RewriteObjCConstString (llvm::GlobalVariable *NSStr, RewriteObjCConstString (llvm::GlobalVariable *NSStr,
llvm::GlobalVariable *CStr, llvm::GlobalVariable *CStr);
llvm::Instruction *FirstEntryInstruction);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// The top-level pass implementation /// The top-level pass implementation
/// ///
/// @param[in] llvm_function
/// The function currently being processed.
///
/// @return /// @return
/// True on success; false otherwise /// True on success; false otherwise
//------------------------------------------------------------------ //------------------------------------------------------------------
bool bool
RewriteObjCConstStrings (llvm::Function &llvm_function); RewriteObjCConstStrings ();
//------------------------------------------------------------------ //------------------------------------------------------------------
/// A basic block-level pass to find all Objective-C method calls and /// A basic block-level pass to find all Objective-C method calls and
@ -686,10 +676,26 @@ private:
/// @return /// @return
/// True on success; false otherwise /// 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 static bool
UnfoldConstant (llvm::Constant *old_constant, UnfoldConstant (llvm::Constant *old_constant,
llvm::Value *new_constant, FunctionValueCache &value_maker,
llvm::Instruction *first_entry_inst); FunctionValueCache &entry_instruction_finder);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Construct a reference to m_reloc_placeholder with a given type /// 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::addr_t IRForTarget::StaticDataAllocator::Allocate()
{ {
lldb_private::Error err; lldb_private::Error err;
@ -62,6 +83,14 @@ lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
return m_allocation; 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, IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
bool resolve_vars, bool resolve_vars,
lldb_private::IRExecutionUnit &execution_unit, lldb_private::IRExecutionUnit &execution_unit,
@ -78,7 +107,8 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
m_error_stream(error_stream), m_error_stream(error_stream),
m_result_store(NULL), m_result_store(NULL),
m_result_is_pointer(false), 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 bool
IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module, IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
llvm::Function &llvm_function)
{ {
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); 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 bool
IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
llvm::GlobalVariable *cstr, llvm::GlobalVariable *cstr)
Instruction *FirstEntryInstruction)
{ {
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); 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); 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, CFSCWB_arguments,
"CFStringCreateWithBytes", "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) if (log)
log->PutCString("Couldn't replace the NSString with the result of the call"); log->PutCString("Couldn't replace the NSString with the result of the call");
@ -789,26 +819,12 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
} }
bool bool
IRForTarget::RewriteObjCConstStrings(Function &llvm_function) IRForTarget::RewriteObjCConstStrings()
{ {
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable(); 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(); for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
vi != ve; vi != ve;
++vi) ++vi)
@ -977,7 +993,7 @@ IRForTarget::RewriteObjCConstStrings(Function &llvm_function)
if (!cstr_array) if (!cstr_array)
cstr_global = NULL; cstr_global = NULL;
if (!RewriteObjCConstString(nsstring_global, cstr_global, FirstEntryInstruction)) if (!RewriteObjCConstString(nsstring_global, cstr_global))
{ {
if (log) if (log)
log->PutCString("Error rewriting the constant string"); 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. // This function does not report errors; its callers are responsible.
bool 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)); 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; return false;
case Instruction::BitCast: case Instruction::BitCast:
{ {
FunctionValueCache bit_cast_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
// UnaryExpr // UnaryExpr
// OperandList[0] is value // OperandList[0] is value
Value *s = constant_expr->getOperand(0); if (constant_expr->getOperand(0) != old_constant)
return constant_expr;
if (s == old_constant) return new BitCastInst(value_maker.GetValue(function),
s = new_constant; constant_expr->getType(),
"",
llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
BitCastInst *bit_cast(new BitCastInst(s, constant_expr->getType(), "", first_entry_inst)); return UnfoldConstant(constant_expr, bit_cast_maker, entry_instruction_finder);
UnfoldConstant(constant_expr, bit_cast, first_entry_inst);
} }
break; break;
case Instruction::GetElementPtr: case Instruction::GetElementPtr:
@ -2205,10 +2226,11 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
// OperandList[0] is base // OperandList[0] is base
// OperandList[1]... are indices // 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); Value *ptr = constant_expr->getOperand(0);
if (ptr == old_constant) if (ptr == old_constant)
ptr = new_constant; ptr = value_maker.GetValue(function);
std::vector<Value*> index_vector; 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); Value *operand = constant_expr->getOperand(operand_index);
if (operand == old_constant) if (operand == old_constant)
operand = new_constant; operand = value_maker.GetValue(function);
index_vector.push_back(operand); index_vector.push_back(operand);
} }
ArrayRef <Value*> indices(index_vector); 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; break;
} }
@ -2245,8 +2268,16 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
} }
else else
{ {
// simple fall-through case for non-constants if (Instruction *inst = llvm::dyn_cast<Instruction>(user))
user->replaceUsesOfWith(old_constant, new_constant); {
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(), decl->getNameAsString().c_str(),
offset); offset);
ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument, offset_int, "", FirstEntryInstruction);
if (value) if (value)
{ {
Value *replacement = NULL;
if (log) if (log)
log->Printf(" Replacing [%s]", PrintValue(value).c_str()); 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 // 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 // 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. // 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) 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 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)) 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 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)) if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
var->eraseFromParent(); var->eraseFromParent();
@ -2544,27 +2594,6 @@ IRForTarget::runOnModule (Module &llvm_module)
m_module = &llvm_module; m_module = &llvm_module;
m_target_data.reset(new DataLayout(m_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) if (log)
{ {
std::string s; 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()); 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()); llvm::Type *intptr_ty = Type::getInt8Ty(m_module->getContext());
m_reloc_placeholder = new llvm::GlobalVariable((*m_module), m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
@ -2589,13 +2639,11 @@ IRForTarget::runOnModule (Module &llvm_module)
GlobalVariable::NotThreadLocal /* ThreadLocal */, GlobalVariable::NotThreadLocal /* ThreadLocal */,
0 /* AddressSpace */); 0 /* AddressSpace */);
Function::iterator bbi;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Replace $__lldb_expr_result with a persistent variable // Replace $__lldb_expr_result with a persistent variable
// //
if (!CreateResultVariable(*function)) if (!CreateResultVariable(*main_function))
{ {
if (log) if (log)
log->Printf("CreateResultVariable() failed"); log->Printf("CreateResultVariable() failed");
@ -2605,6 +2653,29 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; 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(); for (bbi = function->begin();
bbi != function->end(); bbi != function->end();
++bbi) ++bbi)
@ -2639,24 +2710,13 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; 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: // Fix all Objective-C constant strings to use NSStringWithCString:encoding:
// //
if (!RewriteObjCConstStrings(*function)) if (!RewriteObjCConstStrings())
{ {
if (log) if (log)
log->Printf("RewriteObjCConstStrings() failed"); log->Printf("RewriteObjCConstStrings() failed");
@ -2670,7 +2730,7 @@ IRForTarget::runOnModule (Module &llvm_module)
// Resolve function pointers // Resolve function pointers
// //
if (!ResolveFunctionPointers(llvm_module, *function)) if (!ResolveFunctionPointers(llvm_module))
{ {
if (log) if (log)
log->Printf("ResolveFunctionPointers() failed"); log->Printf("ResolveFunctionPointers() failed");
@ -2680,8 +2740,14 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; return false;
} }
for (bbi = function->begin(); for (Module::iterator fi = m_module->begin(), fe = m_module->end();
bbi != function->end(); fi != fe;
++fi)
{
llvm::Function *function = fi;
for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
bbi != bbe;
++bbi) ++bbi)
{ {
if (!RewriteObjCSelectors(*bbi)) if (!RewriteObjCSelectors(*bbi))
@ -2694,9 +2760,16 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; return false;
} }
} }
}
for (bbi = function->begin(); for (Module::iterator fi = m_module->begin(), fe = m_module->end();
bbi != function->end(); fi != fe;
++fi)
{
llvm::Function *function = fi;
for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
bbi != bbe;
++bbi) ++bbi)
{ {
if (!ResolveCalls(*bbi)) if (!ResolveCalls(*bbi))
@ -2717,12 +2790,13 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; 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) if (log)
log->Printf("ResolveExternals() failed"); log->Printf("ResolveExternals() failed");
@ -2732,7 +2806,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false; return false;
} }
if (!ReplaceVariables(*function)) if (!ReplaceVariables(*main_function))
{ {
if (log) if (log)
log->Printf("ReplaceVariables() failed"); log->Printf("ReplaceVariables() failed");