20 #include <boost/thread/mutex.hpp>
22 #include <llvm/ADT/Triple.h>
23 #include <llvm/Analysis/InstructionSimplify.h>
24 #include <llvm/Analysis/Passes.h>
25 #include <llvm/Bitcode/ReaderWriter.h>
26 #include <llvm/ExecutionEngine/ExecutionEngine.h>
27 #include <llvm/ExecutionEngine/JIT.h>
28 #include <llvm/IR/DataLayout.h>
29 #include <llvm/Linker.h>
30 #include <llvm/PassManager.h>
31 #include <llvm/Support/DynamicLibrary.h>
32 #include <llvm/Support/Host.h>
33 #include <llvm/Support/MemoryBuffer.h>
34 #include <llvm/Support/NoFolder.h>
35 #include <llvm/Support/TargetRegistry.h>
36 #include <llvm/Support/TargetSelect.h>
37 #include <llvm/Support/raw_ostream.h>
38 #include <llvm/Support/system_error.h>
39 #include <llvm/Target/TargetLibraryInfo.h>
40 #include <llvm/Transforms/IPO.h>
41 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
42 #include <llvm/Transforms/Scalar.h>
43 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
44 #include <llvm/Transforms/Utils/Cloning.h>
50 #include "impala-ir/impala-ir-names.h"
62 "if true, prints the instruction counts of all JIT'd functions");
65 "if true, disables llvm optimization passes (used for testing)");
66 DEFINE_bool(dump_ir,
false,
"if true, output IR after optimization passes");
68 "if set, saves unoptimized generated IR modules to the specified directory.");
70 "if set, saves optimized generated IR modules to the specified directory.");
78 void LlvmCodeGen::InitializeLlvm(
bool load_backend) {
83 bool result = llvm::llvm_start_multithreaded();
87 llvm::InitializeNativeTarget();
93 PathBuilder::GetFullBuildPath(
"service/libfesupport.so", &path);
94 bool failed = llvm::sys::DynamicLibrary::LoadLibraryPermanently(path.c_str());
101 profile_(pool,
"CodeGen"),
102 optimizations_enabled_(false),
105 context_(new llvm::LLVMContext()),
107 execution_engine_(NULL),
108 debug_trace_fn_(NULL) {
123 const string& file,
const string&
id, scoped_ptr<LlvmCodeGen>* codegen) {
125 SCOPED_TIMER((*codegen)->profile_.total_time_counter());
127 Module* loaded_module;
129 (*codegen)->module_ = loaded_module;
131 return (*codegen)->Init();
136 OwningPtr<MemoryBuffer> file_buffer;
140 llvm::error_code err = MemoryBuffer::getFile(file, file_buffer);
141 if (err.value() != 0) {
143 ss <<
"Could not load module " << file <<
": " << err.message();
152 *module = ParseBitcodeFile(file_buffer.get(), codegen->
context(), &error);
153 if (*module == NULL) {
155 ss <<
"Could not parse module " << file <<
": " << error;
170 Linker::LinkModules(
module_, new_module, Linker::DestroySource, &error_msg);
173 ss <<
"Problem linking " << file <<
" to main module: " << error_msg;
181 ObjectPool*
pool,
const string&
id, scoped_ptr<LlvmCodeGen>* codegen_ret) {
205 const DataLayout* data_layout = codegen->
execution_engine()->getDataLayout();
206 const StructLayout* layout =
207 data_layout->getStructLayout(static_cast<StructType*>(codegen->
string_val_type_));
208 if (layout->getSizeInBytes() !=
sizeof(
StringValue)) {
209 DCHECK_EQ(layout->getSizeInBytes(),
sizeof(
StringValue));
210 return Status(
"Could not create llvm struct type for StringVal");
214 vector<Function*> functions;
216 int parsed_functions = 0;
217 for (
int i = 0; i < functions.size(); ++i) {
218 string fn_name = functions[i]->getName();
219 for (
int j = IRFunction::FN_START; j < IRFunction::FN_END; ++j) {
224 if (fn_name.find(FN_MAPPINGS[j].fn_name) != string::npos) {
226 return Status(
"Duplicate definition found for function: " + fn_name);
228 functions[i]->addFnAttr(Attribute::AlwaysInline);
235 if (parsed_functions != IRFunction::FN_END) {
237 ss <<
"Unable to find these precompiled functions: ";
239 for (
int i = IRFunction::FN_START; i != IRFunction::FN_END; ++i) {
241 if (!first) ss <<
", ";
242 ss << FN_MAPPINGS[i].fn_name;
256 llvm::CodeGenOpt::Level opt_level = CodeGenOpt::Aggressive;
261 opt_level = CodeGenOpt::None;
263 EngineBuilder builder = EngineBuilder(
module_).setOptLevel(opt_level);
301 raw_string_ostream stream(str);
315 return Type::getInt1Ty(
context());
317 return Type::getInt1Ty(
context());
319 return Type::getInt8Ty(
context());
321 return Type::getInt16Ty(
context());
323 return Type::getInt32Ty(
context());
325 return Type::getInt64Ty(
context());
327 return Type::getFloatTy(
context());
329 return Type::getDoubleTy(
context());
339 DCHECK(
false) <<
"Invalid type: " << type;
345 return PointerType::get(
GetType(type), 0);
349 Type* type =
module_->getTypeByName(name);
350 DCHECK_NOTNULL(type);
356 DCHECK(type != NULL) <<
name;
357 return PointerType::get(type, 0);
361 return PointerType::get(type, 0);
367 Constant* const_int = ConstantInt::get(Type::getInt64Ty(
context()), (int64_t)ptr);
368 return ConstantExpr::getIntToPtr(const_int, type);
374 return ConstantInt::get(
context(), APInt(8, val));
376 return ConstantInt::get(
context(), APInt(16, val));
378 return ConstantInt::get(
context(), APInt(32, val));
380 return ConstantInt::get(
context(), APInt(64, val));
388 IRBuilder<> tmp(&f->getEntryBlock(), f->getEntryBlock().begin());
389 AllocaInst* alloca = tmp.CreateAlloca(var.type, 0, var.name.c_str());
394 alloca->setAlignment(16);
402 NamedVariable(name, type));
406 const string& else_name, BasicBlock** if_block, BasicBlock** else_block,
407 BasicBlock* insert_before) {
408 *if_block = BasicBlock::Create(
context(), if_name, fn, insert_before);
409 *else_block = BasicBlock::Create(
context(), else_name, fn, insert_before);
435 for (Function::iterator i = fn->begin(), e = fn->end(); i != e; ++i) {
436 if (i->empty() || !i->back().isTerminator()) {
437 LOG(ERROR) <<
"Basic block must end with terminator: \n" <<
Print(&(*i));
446 string fn_name = fn->getName();
447 LOG(ERROR) <<
"Function corrupt: " <<
fn_name;
455 LlvmCodeGen* gen,
const string& name, Type* ret_type) :
456 codegen_(gen), name_(name), ret_type_(ret_type) {
462 vector<Type*> arguments;
463 for (
int i = 0; i < args_.size(); ++i) {
464 arguments.push_back(args_[i].type);
466 FunctionType* prototype = FunctionType::get(ret_type_, arguments,
false);
468 Function* fn = Function::Create(
469 prototype, Function::ExternalLinkage, name_, codegen_->module_);
474 for (Function::arg_iterator iter = fn->arg_begin();
475 iter != fn->arg_end(); ++iter, ++
idx) {
476 iter->setName(args_[idx].name);
477 if (params != NULL) params[
idx] = iter;
480 if (builder != NULL) {
481 BasicBlock* entry_block = BasicBlock::Create(codegen_->context(),
"entry", fn);
482 builder->SetInsertPoint(entry_block);
485 codegen_->codegend_functions_.push_back(fn);
490 Function* new_fn,
const string& replacee_name,
int* replaced) {
491 DCHECK(caller->getParent() ==
module_);
492 DCHECK(caller != NULL);
493 DCHECK(new_fn != NULL);
495 if (!update_in_place) {
505 Function::iterator block_iter = caller->begin();
506 while (block_iter != caller->end()) {
507 BasicBlock* block = block_iter++;
509 BasicBlock::iterator instr_iter = block->begin();
510 while (instr_iter != block->end()) {
511 Instruction* instr = instr_iter++;
513 if (CallInst::classof(instr)) {
514 CallInst* call_instr =
reinterpret_cast<CallInst*
>(instr);
515 Function* old_fn = call_instr->getCalledFunction();
517 if (old_fn != NULL && old_fn->getName().find(replacee_name) != string::npos) {
519 call_instr->setCalledFunction(new_fn);
530 ValueToValueMapTy dummy_vmap;
532 Function* fn_clone = llvm::CloneFunction(fn, dummy_vmap,
false);
533 fn_clone->copyAttributesFrom(fn);
534 module_->getFunctionList().push_back(fn_clone);
542 int functions_inlined = 0;
544 vector<CallInst*> call_sites;
547 Function::iterator block_iter = fn->begin();
548 while (block_iter != fn->end()) {
549 BasicBlock* block = block_iter++;
551 BasicBlock::iterator instr_iter = block->begin();
552 while (instr_iter != block->end()) {
553 Instruction* instr = instr_iter++;
555 if (CallInst::classof(instr)) {
556 CallInst* call_instr =
reinterpret_cast<CallInst*
>(instr);
557 Function* called_fn = call_instr->getCalledFunction();
559 if (called_fn == NULL || !called_fn->hasFnAttribute(Attribute::AlwaysInline)) {
562 if (skip_registered_fns) {
567 call_sites.push_back(call_instr);
574 for (
int i = 0; i < call_sites.size(); ++i) {
575 llvm::InlineFunctionInfo info;
576 if (llvm::InlineFunction(call_sites[i], info)) {
580 return functions_inlined;
588 }
while (num_inlined > 0);
597 function->addFnAttr(llvm::Attribute::AlwaysInline);
600 function->eraseFromParent();
603 if (FLAGS_dump_ir)
function->dump();
611 if (FLAGS_unopt_module_dir.size() != 0) {
612 string path = FLAGS_unopt_module_dir +
"/" +
id_ +
"_unopt.ll";
613 fstream f(path.c_str(), fstream::out | fstream::trunc);
615 LOG(ERROR) <<
"Could not save IR to: " <<
path;
638 if (FLAGS_opt_module_dir.size() != 0) {
639 string path = FLAGS_opt_module_dir +
"/" +
id_ +
"_opt.ll";
640 fstream f(path.c_str(), fstream::out | fstream::trunc);
642 LOG(ERROR) <<
"Could not save IR to: " <<
path;
660 PassManagerBuilder pass_builder ;
664 pass_builder.OptLevel = 2;
666 pass_builder.SizeLevel = 0;
667 pass_builder.Inliner = createFunctionInliningPass() ;
671 const string& data_layout_str =
module_->getDataLayout();
672 DCHECK(!data_layout_str.empty());
679 vector<const char*> exported_fn_names;
683 scoped_ptr<PassManager> module_pass_manager(
new PassManager());
684 module_pass_manager->add(
new DataLayout(data_layout_str));
685 module_pass_manager->add(createInternalizePass(exported_fn_names));
686 module_pass_manager->add(createGlobalDCEPass());
687 module_pass_manager->run(*
module_);
690 scoped_ptr<FunctionPassManager> fn_pass_manager(
new FunctionPassManager(
module_));
691 fn_pass_manager->add(
new DataLayout(data_layout_str));
692 pass_builder.populateFunctionPassManager(*fn_pass_manager);
693 fn_pass_manager->doInitialization();
694 for (Module::iterator it =
module_->begin(), end =
module_->end(); it != end ; ++it) {
695 if (!it->isDeclaration()) fn_pass_manager->run(*it);
697 fn_pass_manager->doFinalization();
700 module_pass_manager.reset(
new PassManager());
701 module_pass_manager->add(
new DataLayout(data_layout_str));
702 pass_builder.populateModulePassManager(*module_pass_manager);
703 module_pass_manager->run(*
module_);
704 if (FLAGS_print_llvm_ir_instruction_count) {
716 if (fn->getReturnType() == decimal_val_type) {
723 name << fn->getName().str() <<
"ABIWrapper";
728 for (Function::arg_iterator arg = fn->arg_begin(); arg != fn->arg_end(); ++arg) {
729 prototype.AddArgument(
NamedVariable(arg->getName(), arg->getType()));
732 Value* args[fn->arg_size() + 1];
733 Function* fn_wrapper = prototype.GeneratePrototype(&builder, &args[0]);
734 fn_wrapper->addFnAttr(llvm::Attribute::AlwaysInline);
736 fn_wrapper->addAttribute(1, Attribute::StructRet);
739 builder.CreateCall(fn, ArrayRef<Value*>(&args[1], fn->arg_size()),
"result");
740 builder.CreateStore(result, args[0]);
741 builder.CreateRetVoid();
754 if (jitted_function != NULL) {
757 return jitted_function;
762 printf(
"LLVM Trace: %s\n", str);
766 LOG(ERROR) <<
"Remove IR codegen debug traces before checking in.";
772 FunctionType* fn_type = FunctionType::get(
void_type_, args,
false);
773 debug_trace_fn_ = Function::Create(fn_type, GlobalValue::ExternalLinkage,
795 vector<Value*> calling_args;
796 calling_args.push_back(str_ptr);
801 Module::iterator fn_iter =
module_->begin();
802 while (fn_iter !=
module_->end()) {
803 Function* fn = fn_iter++;
804 if (!fn->empty()) functions->push_back(fn);
809 Module::iterator fn_iter =
module_->begin();
810 while (fn_iter !=
module_->end()) {
811 Function* fn = fn_iter++;
812 if (!fn->empty()) symbols->insert(fn->getName());
839 Value* compare = NULL;
847 compare = builder.CreateAnd(params[0], params[1]);
850 compare = builder.CreateOr(params[0], params[1]);
858 compare = builder.CreateICmpSLT(params[0], params[1]);
860 compare = builder.CreateICmpSGT(params[0], params[1]);
866 compare = builder.CreateFCmpULT(params[0], params[1]);
868 compare = builder.CreateFCmpUGT(params[0], params[1]);
876 builder.CreateRet(compare);
878 BasicBlock* ret_v1, *ret_v2;
881 builder.CreateCondBr(compare, ret_v1, ret_v2);
882 builder.SetInsertPoint(ret_v1);
883 builder.CreateRet(params[0]);
884 builder.SetInsertPoint(ret_v2);
885 builder.CreateRet(params[1]);
899 Function* fn = Intrinsic::getDeclaration(
module(), Intrinsic::memcpy, types);
901 return Status(
"Could not find memcpy intrinsic.");
910 } non_overloaded_intrinsics[] = {
911 { Intrinsic::x86_sse42_crc32_32_8,
"sse4.2 crc32_u8" },
912 { Intrinsic::x86_sse42_crc32_32_16,
"sse4.2 crc32_u16" },
913 { Intrinsic::x86_sse42_crc32_32_32,
"sse4.2 crc32_u32" },
914 { Intrinsic::x86_sse42_crc32_64_64,
"sse4.2 crc32_u64" },
916 const int num_intrinsics =
917 sizeof(non_overloaded_intrinsics) /
sizeof(non_overloaded_intrinsics[0]);
919 for (
int i = 0; i < num_intrinsics; ++i) {
920 Intrinsic::ID
id = non_overloaded_intrinsics[i].id;
921 Function* fn = Intrinsic::getDeclaration(
module(),
id);
924 ss <<
"Could not find " << non_overloaded_intrinsics[i].error <<
" intrinsic";
935 if (size == 0)
return;
938 DCHECK(PointerType::classof(dst->getType()));
939 DCHECK(PointerType::classof(src->getType()));
940 dst = builder->CreateBitCast(dst,
ptr_type());
941 src = builder->CreateBitCast(src,
ptr_type());
945 DCHECK(memcpy_fn != NULL);
955 builder->CreateCall(memcpy_fn, args);
987 if (num_bytes == -1) {
993 map<int, Function*>::iterator cached_fn =
hash_fns_.find(num_bytes);
995 return cached_fn->second;
1000 ss <<
"CrcHash" << num_bytes;
1008 Function* fn = prototype.GeneratePrototype(&builder, &args[0]);
1009 Value* data = args[0];
1010 Value* result = args[2];
1018 if (num_bytes >= 8) {
1022 while (num_bytes >= 8) {
1024 Value* d = builder.CreateLoad(builder.CreateGEP(ptr, index));
1025 result_64 = builder.CreateCall2(crc64_fn, result_64, d);
1031 data = builder.CreateGEP(data, index);
1034 if (num_bytes >= 4) {
1035 DCHECK_LT(num_bytes, 8);
1037 Value* d = builder.CreateLoad(ptr);
1038 result = builder.CreateCall2(crc32_fn, result, d);
1040 data = builder.CreateGEP(data, index);
1044 if (num_bytes >= 2) {
1045 DCHECK_LT(num_bytes, 4);
1047 Value* d = builder.CreateLoad(ptr);
1048 result = builder.CreateCall2(crc16_fn, result, d);
1050 data = builder.CreateGEP(data, index);
1054 if (num_bytes > 0) {
1055 DCHECK_EQ(num_bytes, 1);
1056 Value* d = builder.CreateLoad(data);
1057 result = builder.CreateCall2(crc8_fn, result, d);
1060 DCHECK_EQ(num_bytes, 0);
1063 Value* upper_bits = builder.CreateShl(result, shift_16);
1064 Value* lower_bits = builder.CreateLShr(result, shift_16);
1065 result = builder.CreateOr(upper_bits, lower_bits);
1066 builder.CreateRet(result);
1079 LlvmCodeGen* codegen, IRFunction::Type f,
int len) {
1101 BasicBlock::iterator iter(from);
1102 llvm::ReplaceInstWithValue(from->getParent()->getInstList(), iter, to);
1106 DCHECK_LE(i, fn->arg_size());
1107 Function::arg_iterator iter = fn->arg_begin();
1108 for (
int j = 0; j < i; ++j) ++iter;
boost::scoped_ptr< llvm::ExecutionEngine > execution_engine_
Execution/Jitting engine.
std::string error_string_
Error string that llvm will write to.
static Status LoadImpalaIR(ObjectPool *, const std::string &id, boost::scoped_ptr< LlvmCodeGen > *codegen)
~LlvmCodeGen()
Removes all jit compiled dynamically linked functions from the process.
string path("/usr/lib/sasl2:/usr/lib64/sasl2:/usr/local/lib/sasl2:/usr/lib/x86_64-linux-gnu/sasl2")
llvm::PointerType * GetPtrType(llvm::Type *type)
Return a pointer type to 'type'.
void OptimizeModule()
Optimizes the module. This includes pruning the module of any unused functions.
const std::string & name() const
Returns name of function.
Utility struct that wraps a variable name and llvm type.
std::set< std::string > linked_modules_
llvm::Function * CodegenMinMax(const ColumnType &type, bool min)
Generates function to return min/max(v1, v2)
#define RETURN_IF_ERROR(stmt)
some generally useful macros
std::map< llvm::Intrinsic::ID, llvm::Function * > llvm_intrinsics_
A cache of loaded llvm intrinsics.
Status Init()
Initializes the jitter and execution engine.
int InlineCallSites(llvm::Function *fn, bool skip_registered_fns)
#define ADD_TIMER(profile, name)
std::vector< llvm::Function * > loaded_functions_
Functions parsed from pre-compiled module. Indexed by ImpalaIR::Function enum.
std::string GetIR(bool full_module) const
RuntimeProfile profile_
Codegen counters.
std::vector< std::string > debug_strings_
DEFINE_bool(print_llvm_ir_instruction_count, false,"if true, prints the instruction counts of all JIT'd functions")
llvm::Function * GetLibCFunction(FnPrototype *prototype)
Returns the libc function, adding it to the module if it has not already been.
void ReplaceInstWithValue(llvm::Instruction *from, llvm::Value *to)
LlvmCodeGen(ObjectPool *pool, const std::string &module_id)
Top level codegen object. 'module_id' is used for debugging when outputting the IR.
#define COUNTER_ADD(c, v)
llvm::Argument * GetArgument(llvm::Function *fn, int i)
Returns the i-th argument of fn.
RuntimeProfile::Counter * codegen_timer_
Time spent doing codegen (adding IR to the module)
llvm::Value * false_value_
static bool llvm_initialized
llvm::PointerType * ptr_type_
llvm representation of a few common types. Owned by context.
static std::string Print(T *value_or_type)
Returns the string representation of a llvm::Value* or llvm::Type*.
LLVM code generator. This is the top level object to generate jitted code.
RuntimeProfile::Counter * module_file_size_
llvm::Function * debug_trace_fn_
llvm::Function * GeneratePrototype(LlvmBuilder *builder=NULL, llvm::Value **params=NULL)
llvm::Value * CastPtrToLlvmPtr(llvm::Type *type, const void *ptr)
void AddArgument(const NamedVariable &var)
Add argument.
std::set< llvm::Function * > registered_exprs_
A set of all the functions in 'registered_exprs_map_' for quick lookup.
llvm::Function * GetHashFunction(int num_bytes=-1)
void CodegenMemcpy(LlvmBuilder *, llvm::Value *dst, llvm::Value *src, int size)
llvm::ExecutionEngine * execution_engine()
Returns execution engine interface.
Status LinkModule(const std::string &file)
std::map< llvm::Function *, bool > jitted_functions_
llvm::Type * string_val_type_
int GetByteSize() const
Returns the byte size of this type. Returns 0 for variable length types.
std::string PrintCounters() const
Prints all counters.
static void GetFullPath(const std::string &path, std::string *full_path)
Sets full_path to <IMPALA_HOME>/path.
#define ADD_COUNTER(profile, name, unit)
void ClearHashFns()
Clears generated hash fns. This is only used for testing.
llvm::Function * GetFunction(IRFunction::Type)
llvm::Value * true_value_
llvm constants to help with code gen verbosity
bool VerifyFunction(llvm::Function *function)
static const int64_t SSE4_2
void CreateIfElseBlocks(llvm::Function *fn, const std::string &if_name, const std::string &else_name, llvm::BasicBlock **if_block, llvm::BasicBlock **else_block, llvm::BasicBlock *insert_before=NULL)
void AddFunctionToJit(llvm::Function *fn, void **fn_ptr)
llvm::Function * CloneFunction(llvm::Function *fn)
Returns a copy of fn. The copy is added to the module.
DECLARE_string(local_library_dir)
FnPrototype(LlvmCodeGen *, const std::string &name, llvm::Type *ret_type)
void DebugTrace(const char *str)
std::vector< std::pair< llvm::Function *, void ** > > fns_to_jit_compile_
The vector of functions to automatically JIT compile after FinalizeModule().
static mutex llvm_initialization_lock
void visit(const llvm::Module &M)
Visits each Function in Module M.
static const char * LLVM_CLASS_NAME
std::string id_
ID used for debugging (can be e.g. the fragment instance ID)
llvm::Value * false_value()
llvm::Function * GetFnvHashFunction(int num_bytes=-1)
std::map< std::string, llvm::Function * > external_functions_
std::vector< llvm::Function * > codegend_functions_
static Function * GetLenOptimizedHashFn(LlvmCodeGen *codegen, IRFunction::Type f, int len)
RuntimeProfile::Counter * prepare_module_timer_
Time spent constructing the in-memory module from the .ir file.
llvm::Type * GetType(const ColumnType &type)
Returns llvm type for the column type.
boost::mutex jitted_functions_lock_
Lock protecting jitted_functions_.
static const char * LLVM_CLASS_NAME
For C++/IR interop, we need to be able to look up types by name.
llvm::Value * GetIntConstant(PrimitiveType type, int64_t val)
Returns the constant 'val' of 'type'.
std::map< int, llvm::Function * > hash_fns_
llvm::Function * FinalizeFunction(llvm::Function *function)
static const char * LLVM_DECIMALVAL_NAME
RuntimeProfile::Counter * load_module_timer_
Time spent reading the .ir file from the file system.
llvm::Function * GetMurmurHashFunction(int num_bytes=-1)
void CodegenDebugTrace(LlvmBuilder *builder, const char *message)
llvm::Function * ReplaceCallSites(llvm::Function *caller, bool update_in_place, llvm::Function *new_fn, const std::string &target_name, int *num_replaced)
void EnableOptimizations(bool enable)
Turns on/off optimization passes.
RuntimeProfile::Counter * optimization_timer_
Time spent optimizing the module.
void GetSymbols(boost::unordered_set< std::string > *symbols)
Fils in 'symbols' with all the symbols in the module.
llvm::LLVMContext & context()
void * JitFunction(llvm::Function *function)
bool optimizations_enabled_
whether or not optimizations are enabled
llvm::AllocaInst * CreateEntryBlockAlloca(llvm::Function *f, const NamedVariable &var)
llvm::Function * OptimizeFunctionWithExprs(llvm::Function *fn)
static bool IsSupported(long flag)
Returns whether of not the cpu supports this flag.
static Status LoadFromFile(ObjectPool *, const std::string &file, const std::string &id, boost::scoped_ptr< LlvmCodeGen > *codegen)
llvm::PointerType * ptr_type()
void GetFunctions(std::vector< llvm::Function * > *functions)
static Status LoadModule(LlvmCodeGen *codegen, const std::string &file, llvm::Module **module)
llvm::Type * timestamp_val_type_
RuntimeProfile::Counter * compile_timer_
Time spent compiling the module.
DEFINE_string(unopt_module_dir,"","if set, saves unoptimized generated IR modules to the specified directory.")
llvm::Module * module()
Returns the underlying llvm module.
Counter * total_time_counter()
Returns the counter for the total elapsed time.