diff options
Diffstat (limited to 'lib/Module/KModule.cpp')
-rw-r--r-- | lib/Module/KModule.cpp | 147 |
1 files changed, 94 insertions, 53 deletions
diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index 1629bb79..d889b51f 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -22,31 +22,37 @@ #include "klee/Internal/Support/ModuleUtil.h" #include "llvm/Bitcode/ReaderWriter.h" +#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/DataLayout.h" +#else #include "llvm/Instructions.h" -#if LLVM_VERSION_CODE >= LLVM_VERSION(2, 7) #include "llvm/LLVMContext.h" -#endif #include "llvm/Module.h" -#include "llvm/PassManager.h" #include "llvm/ValueSymbolTable.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/raw_ostream.h" -#if LLVM_VERSION_CODE >= LLVM_VERSION(2, 7) -#include "llvm/Support/raw_os_ostream.h" -#endif -#if LLVM_VERSION_CODE < LLVM_VERSION(2, 9) -#include "llvm/System/Path.h" -#else -#include "llvm/Support/Path.h" -#endif #if LLVM_VERSION_CODE <= LLVM_VERSION(3, 1) #include "llvm/Target/TargetData.h" #else #include "llvm/DataLayout.h" #endif + +#endif + +#include "llvm/PassManager.h" +#include "llvm/Support/CallSite.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/Path.h" #include "llvm/Transforms/Scalar.h" +#include <llvm/Transforms/Utils/Cloning.h> +#include <llvm/Support/InstIterator.h> +#include <llvm/Support/Debug.h> + #include <sstream> using namespace llvm; @@ -99,7 +105,6 @@ KModule::KModule(Module *_module) #else targetData(new DataLayout(module)), #endif - dbgStopPointFn(0), kleeMergeFn(0), infos(0), constantTable(0) { @@ -113,6 +118,10 @@ KModule::~KModule() { ie = functions.end(); it != ie; ++it) delete *it; + for (std::map<llvm::Constant*, KConstant*>::iterator it=constantMap.begin(), + itE=constantMap.end(); it!=itE;++it) + delete it->second; + delete targetData; delete module; } @@ -189,6 +198,7 @@ static void injectStaticConstructorsAndDestructors(Module *m) { } } +#if LLVM_VERSION_CODE < LLVM_VERSION(3, 3) static void forceImport(Module *m, const char *name, LLVM_TYPE_Q Type *retType, ...) { // If module lacks an externally visible symbol for the name then we @@ -211,6 +221,53 @@ static void forceImport(Module *m, const char *name, LLVM_TYPE_Q Type *retType, m->getOrInsertFunction(name, FunctionType::get(retType, argTypes, false)); } } +#endif + +/// This function will take try to inline all calls to \p functionName +/// in the module \p module . +/// +/// It is intended that this function be used for inling calls to +/// check functions like <tt>klee_div_zero_check()</tt> +static void inlineChecks(Module *module, const char * functionName) { + std::vector<CallInst*> checkCalls; + Function* runtimeCheckCall = module->getFunction(functionName); + if (runtimeCheckCall == 0) + { + DEBUG( klee_warning("Failed to inline %s because no calls were made to it in module", functionName) ); + return; + } + + // Iterate through instructions in module and collect all + // call instructions to "functionName" that we care about. + for (Module::iterator f = module->begin(), fe = module->end(); f != fe; ++f) { + for (inst_iterator i=inst_begin(f), ie = inst_end(f); i != ie; ++i) { + if ( CallInst* ci = dyn_cast<CallInst>(&*i) ) + { + if ( ci->getCalledFunction() == runtimeCheckCall) + checkCalls.push_back(ci); + } + } + } + + unsigned int successCount=0; + unsigned int failCount=0; + InlineFunctionInfo IFI(0,0); + for ( std::vector<CallInst*>::iterator ci = checkCalls.begin(), + cie = checkCalls.end(); + ci != cie; ++ci) + { + // Try to inline the function + if (InlineFunction(*ci,IFI)) + ++successCount; + else + { + ++failCount; + klee_warning("Failed to inline function %s", functionName); + } + } + + DEBUG( klee_message("Tried to inline calls to %s. %u successes, %u failures",functionName, successCount, failCount) ); +} void KModule::prepare(const Interpreter::ModuleOptions &opts, InterpreterHandler *ih) { @@ -272,6 +329,7 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, PassManager pm; pm.add(new RaiseAsmPass()); if (opts.CheckDivZero) pm.add(new DivCheckPass()); + if (opts.CheckOvershift) pm.add(new OvershiftCheckPass()); // FIXME: This false here is to work around a bug in // IntrinsicLowering which caches values which may eventually be // deleted (via RAUW). This can be removed once LLVM fixes this @@ -281,7 +339,7 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, if (opts.Optimize) Optimize(module); - +#if LLVM_VERSION_CODE < LLVM_VERSION(3, 3) // Force importing functions required by intrinsic lowering. Kind of // unfortunate clutter when we don't need them but we won't know // that until after all linking and intrinsic lowering is @@ -302,16 +360,33 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, PointerType::getUnqual(i8Ty), Type::getInt32Ty(getGlobalContext()), targetData->getIntPtrType(getGlobalContext()), (Type*) 0); - +#endif // FIXME: Missing force import for various math functions. // FIXME: Find a way that we can test programs without requiring // this to be linked in, it makes low level debugging much more // annoying. llvm::sys::Path path(opts.LibraryDir); +#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) + path.appendComponent("kleeRuntimeIntrinsic.bc"); +#else path.appendComponent("libkleeRuntimeIntrinsic.bca"); +#endif module = linkWithLibrary(module, path.c_str()); + /* In order for KLEE to report ALL errors at instrumented + * locations the instrumentation call (e.g. "klee_div_zero_check") + * must be inlined. Otherwise one of the instructions in the + * instrumentation function will be used as the the location of + * the error which means that the error cannot be recorded again + * ( unless -emit-all-errors is used). + */ + if (opts.CheckDivZero) + inlineChecks(module, "klee_div_zero_check"); + if (opts.CheckOvershift) + inlineChecks(module, "klee_overshift_check"); + + // Needs to happen after linking (since ctors/dtors can be modified) // and optimization (since global optimization can rewrite lists). injectStaticConstructorsAndDestructors(module); @@ -332,7 +407,7 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, pm3.add(new IntrinsicCleanerPass(*targetData)); pm3.add(new PhiCleanerPass()); pm3.run(*module); - +#if LLVM_VERSION_CODE < LLVM_VERSION(3, 3) // For cleanliness see if we can discard any of the functions we // forced to import. Function *f; @@ -342,7 +417,7 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, if (f && f->use_empty()) f->eraseFromParent(); f = module->getFunction("memset"); if (f && f->use_empty()) f->eraseFromParent(); - +#endif // Write out the .ll assembly file. We truncate long lines to work // around a kcachegrind parsing bug (it puts them on new lines), so @@ -351,38 +426,6 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, std::ostream *os = ih->openOutputFile("assembly.ll"); assert(os && os->good() && "unable to open source output"); -#if LLVM_VERSION_CODE < LLVM_VERSION(2, 6) - // We have an option for this in case the user wants a .ll they - // can compile. - if (NoTruncateSourceLines) { - os << *module; - } else { - bool truncated = false; - std::string string; - llvm::raw_string_ostream rss(string); - rss << *module; - rss.flush(); - const char *position = string.c_str(); - - for (;;) { - const char *end = index(position, '\n'); - if (!end) { - os << position; - break; - } else { - unsigned count = (end - position) + 1; - if (count<255) { - os->write(position, count); - } else { - os->write(position, 254); - os << "\n"; - truncated = true; - } - position = end+1; - } - } - } -#else llvm::raw_os_ostream *ros = new llvm::raw_os_ostream(*os); // We have an option for this in case the user wants a .ll they @@ -414,7 +457,6 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, } } delete ros; -#endif delete os; } @@ -427,7 +469,6 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, delete f; } - dbgStopPointFn = module->getFunction("llvm.dbg.stoppoint"); kleeMergeFn = module->getFunction("klee_merge"); /* Build shadow structures */ |