diff options
-rw-r--r-- | lib/Module/CMakeLists.txt | 14 | ||||
-rw-r--r-- | lib/Module/Instrument.cpp | 19 | ||||
-rw-r--r-- | lib/Module/InstrumentLegacy.cpp | 125 | ||||
-rw-r--r-- | lib/Module/KModule.cpp | 139 | ||||
-rw-r--r-- | lib/Module/ModuleHelper.h | 37 | ||||
-rw-r--r-- | lib/Module/Optimize.cpp | 249 | ||||
-rw-r--r-- | lib/Module/OptimizeLegacy.cpp | 249 |
7 files changed, 475 insertions, 357 deletions
diff --git a/lib/Module/CMakeLists.txt b/lib/Module/CMakeLists.txt index e1f548e8..71e1d40c 100644 --- a/lib/Module/CMakeLists.txt +++ b/lib/Module/CMakeLists.txt @@ -16,12 +16,24 @@ set(KLEE_MODULE_COMPONENT_SRCS KModule.cpp LowerSwitch.cpp ModuleUtil.cpp - Optimize.cpp OptNone.cpp PhiCleaner.cpp RaiseAsm.cpp ) +if ("${LLVM_VERSION_MAJOR}" LESS 17) + LIST(APPEND KLEE_MODULE_COMPONENT_SRCS + InstrumentLegacy.cpp + OptimizeLegacy.cpp + ) +else () + LIST(APPEND KLEE_MODULE_COMPONENT_SRCS + Instrument.cpp + Optimize.cpp + ) +endif () + + add_library(kleeModule ${KLEE_MODULE_COMPONENT_SRCS} ) diff --git a/lib/Module/Instrument.cpp b/lib/Module/Instrument.cpp new file mode 100644 index 00000000..bbb5df7c --- /dev/null +++ b/lib/Module/Instrument.cpp @@ -0,0 +1,19 @@ +//===-- Instrument.cpp ------------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModuleHelper.h" + +using namespace klee; + +void klee::checkModule(bool DontVerfify, llvm::Module *module) { assert(0); } + +void klee::instrument(bool CheckDivZero, bool CheckOvershift, + llvm::Module *module) { + assert(0); +} \ No newline at end of file diff --git a/lib/Module/InstrumentLegacy.cpp b/lib/Module/InstrumentLegacy.cpp new file mode 100644 index 00000000..daae8043 --- /dev/null +++ b/lib/Module/InstrumentLegacy.cpp @@ -0,0 +1,125 @@ +//===-- InstrumentLegacy.cpp ------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "ModuleHelper.h" + +#include "Passes.h" +#include "klee/Support/CompilerWarning.h" +#include "klee/Support/ErrorHandling.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/Scalarizer.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/Cloning.h" +DISABLE_WARNING_POP + +using namespace llvm; +using namespace klee; + +void klee::instrument(bool CheckDivZero, bool CheckOvershift, + llvm::Module *module) { + // Inject checks prior to optimization... we also perform the + // invariant transformations that we will end up doing later so that + // optimize is seeing what is as close as possible to the final + // module. + legacy::PassManager pm; + pm.add(new RaiseAsmPass()); + + // This pass will scalarize as much code as possible so that the Executor + // does not need to handle operands of vector type for most instructions + // other than InsertElementInst and ExtractElementInst. + // + // NOTE: Must come before division/overshift checks because those passes + // don't know how to handle vector instructions. + pm.add(createScalarizerPass()); + + // This pass will replace atomic instructions with non-atomic operations + pm.add(createLowerAtomicPass()); + if (CheckDivZero) + pm.add(new DivCheckPass()); + if (CheckOvershift) + pm.add(new OvershiftCheckPass()); + + llvm::DataLayout targetData(module); + pm.add(new IntrinsicCleanerPass(targetData)); + pm.run(*module); +} + +void klee::checkModule(bool DontVerify, llvm::Module *module) { + InstructionOperandTypeCheckPass *operandTypeCheckPass = + new InstructionOperandTypeCheckPass(); + + legacy::PassManager pm; + if (!DontVerify) + pm.add(createVerifierPass()); + pm.add(operandTypeCheckPass); + pm.run(*module); + + // Enforce the operand type invariants that the Executor expects. This + // implicitly depends on the "Scalarizer" pass to be run in order to succeed + // in the presence of vector instructions. + if (!operandTypeCheckPass->checkPassed()) { + klee_error("Unexpected instruction operand types detected"); + } +} + +void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + SwitchImplType SwitchType, std::string EntryPoint, + llvm::ArrayRef<const char *> preservedFunctions, + llvm::Module *module) { + // Preserve all functions containing klee-related function calls from being + // optimised around + if (!OptimiseKLEECall) { + legacy::PassManager pm; + pm.add(new OptNonePass()); + pm.run(*module); + } + + if (Optimize) + optimizeModule(module, preservedFunctions); + + // Needs to happen after linking (since ctors/dtors can be modified) + // and optimization (since global optimization can rewrite lists). + injectStaticConstructorsAndDestructors(module, EntryPoint); + + // Finally, run the passes that maintain invariants we expect during + // interpretation. We run the intrinsic cleaner just in case we + // linked in something with intrinsics but any external calls are + // going to be unresolved. We really need to handle the intrinsics + // directly I think? + legacy::PassManager pm3; + pm3.add(createCFGSimplificationPass()); + switch (SwitchType) { + case SwitchImplType::eSwitchTypeInternal: + break; + case SwitchImplType::eSwitchTypeSimple: + pm3.add(new LowerSwitchPass()); + break; + case SwitchImplType::eSwitchTypeLLVM: + pm3.add(createLowerSwitchPass()); + break; + } + + llvm::DataLayout targetData(module); + pm3.add(new IntrinsicCleanerPass(targetData)); + pm3.add(createScalarizerPass()); + pm3.add(new PhiCleanerPass()); + pm3.add(new FunctionAliasPass()); + pm3.run(*module); +} \ No newline at end of file diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index eed922f8..cb8b4539 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -9,40 +9,27 @@ #define DEBUG_TYPE "KModule" +#include "klee/Module/KModule.h" + +#include "ModuleHelper.h" #include "Passes.h" #include "klee/Config/Version.h" #include "klee/Core/Interpreter.h" -#include "klee/Support/OptionCategories.h" #include "klee/Module/Cell.h" #include "klee/Module/InstructionInfoTable.h" #include "klee/Module/KInstruction.h" -#include "klee/Module/KModule.h" #include "klee/Support/Debug.h" #include "klee/Support/ErrorHandling.h" #include "klee/Support/ModuleUtil.h" +#include "klee/Support/OptionCategories.h" #include "klee/Support/CompilerWarning.h" + DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/Bitcode/BitcodeWriter.h" -#include "llvm/IR/DataLayout.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/ValueSymbolTable.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Linker/Linker.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/raw_os_ostream.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Scalar/Scalarizer.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils.h" DISABLE_WARNING_POP #include <sstream> @@ -57,12 +44,6 @@ cl::OptionCategory } namespace { - enum SwitchImplType { - eSwitchTypeSimple, - eSwitchTypeLLVM, - eSwitchTypeInternal - }; - cl::opt<bool> OutputSource("output-source", cl::desc("Write the assembly for the final transformed source (default=true)"), @@ -75,16 +56,6 @@ namespace { cl::init(false), cl::cat(ModuleCat)); - cl::opt<SwitchImplType> - SwitchType("switch-type", cl::desc("Select the implementation of switch (default=internal)"), - cl::values(clEnumValN(eSwitchTypeSimple, "simple", - "lower to ordered branches"), - clEnumValN(eSwitchTypeLLVM, "llvm", - "lower using LLVM"), - clEnumValN(eSwitchTypeInternal, "internal", - "execute switch internally")), - cl::init(eSwitchTypeInternal), - cl::cat(ModuleCat)); cl::opt<bool> DebugPrintEscapingFunctions("debug-print-escaping-functions", @@ -102,14 +73,21 @@ namespace { cl::desc("Allow optimization of functions that " "contain KLEE calls (default=true)"), cl::init(true), cl::cat(ModuleCat)); -} +cl::opt<SwitchImplType> SwitchType( + "switch-type", + cl::desc("Select the implementation of switch (default=internal)"), + cl::values(clEnumValN(SwitchImplType::eSwitchTypeSimple, "simple", + "lower to ordered branches"), + clEnumValN(SwitchImplType::eSwitchTypeLLVM, "llvm", + "lower using LLVM"), + clEnumValN(SwitchImplType::eSwitchTypeInternal, "internal", + "execute switch internally")), + cl::init(SwitchImplType::eSwitchTypeInternal), cl::cat(ModuleCat)); + +} // namespace /***/ -namespace llvm { -extern void Optimize(Module *, llvm::ArrayRef<const char *> preservedFunctions); -} - // what a hack static Function *getStubFunctionForCtorList(Module *m, GlobalVariable *gv, @@ -156,9 +134,8 @@ static Function *getStubFunctionForCtorList(Module *m, return fn; } -static void -injectStaticConstructorsAndDestructors(Module *m, - llvm::StringRef entryFunction) { +void klee::injectStaticConstructorsAndDestructors( + Module *m, llvm::StringRef entryFunction) { GlobalVariable *ctors = m->getNamedGlobal("llvm.global_ctors"); GlobalVariable *dtors = m->getNamedGlobal("llvm.global_dtors"); @@ -216,44 +193,12 @@ bool KModule::link(std::vector<std::unique_ptr<llvm::Module>> &modules, } void KModule::instrument(const Interpreter::ModuleOptions &opts) { - // Inject checks prior to optimization... we also perform the - // invariant transformations that we will end up doing later so that - // optimize is seeing what is as close as possible to the final - // module. - legacy::PassManager pm; - pm.add(new RaiseAsmPass()); - - // This pass will scalarize as much code as possible so that the Executor - // does not need to handle operands of vector type for most instructions - // other than InsertElementInst and ExtractElementInst. - // - // NOTE: Must come before division/overshift checks because those passes - // don't know how to handle vector instructions. - pm.add(createScalarizerPass()); - - // This pass will replace atomic instructions with non-atomic operations - pm.add(createLowerAtomicPass()); - if (opts.CheckDivZero) pm.add(new DivCheckPass()); - if (opts.CheckOvershift) pm.add(new OvershiftCheckPass()); - - pm.add(new IntrinsicCleanerPass(*targetData)); - pm.run(*module); + klee::instrument(opts.CheckDivZero, opts.CheckOvershift, module.get()); } void KModule::optimiseAndPrepare( const Interpreter::ModuleOptions &opts, llvm::ArrayRef<const char *> preservedFunctions) { - // Preserve all functions containing klee-related function calls from being - // optimised around - if (!OptimiseKLEECall) { - legacy::PassManager pm; - pm.add(new OptNonePass()); - pm.run(*module); - } - - if (opts.Optimize) - Optimize(module.get(), preservedFunctions); - // Add internal functions which are not used to check if instructions // have been already visited if (opts.CheckDivZero) @@ -261,28 +206,8 @@ void KModule::optimiseAndPrepare( if (opts.CheckOvershift) addInternalFunction("klee_overshift_check"); - // Needs to happen after linking (since ctors/dtors can be modified) - // and optimization (since global optimization can rewrite lists). - injectStaticConstructorsAndDestructors(module.get(), opts.EntryPoint); - - // Finally, run the passes that maintain invariants we expect during - // interpretation. We run the intrinsic cleaner just in case we - // linked in something with intrinsics but any external calls are - // going to be unresolved. We really need to handle the intrinsics - // directly I think? - legacy::PassManager pm3; - pm3.add(createCFGSimplificationPass()); - switch(SwitchType) { - case eSwitchTypeInternal: break; - case eSwitchTypeSimple: pm3.add(new LowerSwitchPass()); break; - case eSwitchTypeLLVM: pm3.add(createLowerSwitchPass()); break; - default: klee_error("invalid --switch-type"); - } - pm3.add(new IntrinsicCleanerPass(*targetData)); - pm3.add(createScalarizerPass()); - pm3.add(new PhiCleanerPass()); - pm3.add(new FunctionAliasPass()); - pm3.run(*module); + klee::optimiseAndPrepare(OptimiseKLEECall, opts.Optimize, SwitchType, + opts.EntryPoint, preservedFunctions, module.get()); } void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) { @@ -294,7 +219,7 @@ void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) { if (OutputModule) { std::unique_ptr<llvm::raw_fd_ostream> f(ih->openOutputFile("final.bc")); - WriteBitcodeToFile(*module, *f); + llvm::WriteBitcodeToFile(*module, *f); } /* Build shadow structures */ @@ -343,23 +268,7 @@ void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) { } } -void KModule::checkModule() { - InstructionOperandTypeCheckPass *operandTypeCheckPass = - new InstructionOperandTypeCheckPass(); - - legacy::PassManager pm; - if (!DontVerify) - pm.add(createVerifierPass()); - pm.add(operandTypeCheckPass); - pm.run(*module); - - // Enforce the operand type invariants that the Executor expects. This - // implicitly depends on the "Scalarizer" pass to be run in order to succeed - // in the presence of vector instructions. - if (!operandTypeCheckPass->checkPassed()) { - klee_error("Unexpected instruction operand types detected"); - } -} +void KModule::checkModule() { klee::checkModule(DontVerify, module.get()); } KConstant* KModule::getKConstant(const Constant *c) { auto it = constantMap.find(c); diff --git a/lib/Module/ModuleHelper.h b/lib/Module/ModuleHelper.h new file mode 100644 index 00000000..1b279edd --- /dev/null +++ b/lib/Module/ModuleHelper.h @@ -0,0 +1,37 @@ +//===-- ModuleHelper.h ------------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef KLEE_MODULEHELPER_H +#define KLEE_MODULEHELPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/Module.h" + +namespace klee { +enum class SwitchImplType { + eSwitchTypeSimple, + eSwitchTypeLLVM, + eSwitchTypeInternal +}; + +void optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + SwitchImplType SwitchType, std::string EntryPoint, + llvm::ArrayRef<const char *> preservedFunctions, + llvm::Module *module); +void checkModule(bool DontVerfify, llvm::Module *module); +void instrument(bool CheckDivZero, bool CheckOvershift, llvm::Module *module); + +void injectStaticConstructorsAndDestructors(llvm::Module *m, + llvm::StringRef entryFunction); + +void optimizeModule(llvm::Module *M, + llvm::ArrayRef<const char *> preservedFunctions); +} // namespace klee + +#endif // KLEE_MODULEHELPER_H diff --git a/lib/Module/Optimize.cpp b/lib/Module/Optimize.cpp index 35b9805a..9475512b 100644 --- a/lib/Module/Optimize.cpp +++ b/lib/Module/Optimize.cpp @@ -15,247 +15,14 @@ // //===----------------------------------------------------------------------===// -#include "klee/Config/Version.h" -#include "klee/Support/OptionCategories.h" +#include "ModuleHelper.h" -#include "klee/Support/CompilerWarning.h" -DISABLE_WARNING_PUSH -DISABLE_WARNING_DEPRECATED_DECLARATIONS -#include "llvm/Analysis/GlobalsModRef.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/LoopPass.h" #include "llvm/IR/Module.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/PluginLoader.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/InstCombine/InstCombine.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/FunctionAttrs.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Scalar/GVN.h" -#include "llvm/Transforms/Utils.h" -DISABLE_WARNING_POP -using namespace llvm; - -static cl::opt<bool> - DisableInline("disable-inlining", - cl::desc("Do not run the inliner pass (default=false)"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::opt<bool> DisableInternalize( - "disable-internalize", - cl::desc("Do not mark all symbols as internal (default=false)"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::opt<bool> VerifyEach( - "verify-each", - cl::desc("Verify intermediate results of all optimization passes (default=false)"), - cl::init(false), - cl::cat(klee::ModuleCat)); - -static cl::alias ExportDynamic("export-dynamic", - cl::aliasopt(DisableInternalize), - cl::desc("Alias for -disable-internalize")); - -static cl::opt<bool> - Strip("strip-all", cl::desc("Strip all symbol information from executable"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::alias A0("s", cl::desc("Alias for --strip-all"), - cl::aliasopt(Strip)); - -static cl::opt<bool> - StripDebug("strip-debug", - cl::desc("Strip debugger symbol info from executable"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::alias A1("S", cl::desc("Alias for --strip-debug"), - cl::aliasopt(StripDebug)); - -// A utility function that adds a pass to the pass manager but will also add -// a verifier pass after if we're supposed to verify. -static inline void addPass(legacy::PassManager &PM, Pass *P) { - // Add the pass to the pass manager... - PM.add(P); - - // If we are verifying all of the intermediate steps, add the verifier... - if (VerifyEach) - PM.add(createVerifierPass()); -} - -namespace llvm { - - -static void AddStandardCompilePasses(legacy::PassManager &PM) { - PM.add(createVerifierPass()); // Verify that input is correct - - // If the -strip-debug command line option was specified, do it. - if (StripDebug) - addPass(PM, createStripSymbolsPass(true)); - - addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code - addPass(PM, createPromoteMemoryToRegisterPass());// Kill useless allocas - addPass(PM, createGlobalOptimizerPass()); // Optimize out global vars - addPass(PM, createGlobalDCEPass()); // Remove unused fns and globs -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) - addPass(PM, createSCCPPass()); // Constant prop with SCCP -#else - addPass(PM, createIPConstantPropagationPass());// IP Constant Propagation -#endif - addPass(PM, createDeadArgEliminationPass()); // Dead argument elimination - addPass(PM, createInstructionCombiningPass()); // Clean up after IPCP & DAE - addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE - - addPass(PM, createPruneEHPass()); // Remove dead EH info - addPass(PM, createPostOrderFunctionAttrsLegacyPass()); - addPass(PM, createReversePostOrderFunctionAttrsPass()); // Deduce function attrs - - if (!DisableInline) - addPass(PM, createFunctionInliningPass()); // Inline small functions - addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args - - addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. - addPass(PM, createJumpThreadingPass()); // Thread jumps. - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createSROAPass()); // Break up aggregate allocas - addPass(PM, createInstructionCombiningPass()); // Combine silly seq's - - addPass(PM, createTailCallEliminationPass()); // Eliminate tail calls - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createReassociatePass()); // Reassociate expressions - addPass(PM, createLoopRotatePass()); - addPass(PM, createLICMPass()); // Hoist loop invariants - addPass(PM, createLoopUnswitchPass()); // Unswitch loops. - // FIXME : Removing instcombine causes nestedloop regression. - addPass(PM, createInstructionCombiningPass()); - addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars - addPass(PM, createLoopDeletionPass()); // Delete dead loops - addPass(PM, createLoopUnrollPass()); // Unroll small loops - addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller - addPass(PM, createGVNPass()); // Remove redundancies - addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset - addPass(PM, createSCCPPass()); // Constant prop with SCCP - - // Run instcombine after redundancy elimination to exploit opportunities - // opened up by them. - addPass(PM, createInstructionCombiningPass()); - - addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores - addPass(PM, createAggressiveDCEPass()); // Delete dead instructions - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createStripDeadPrototypesPass()); // Get rid of dead prototypes - addPass(PM, createConstantMergePass()); // Merge dup global constants -} - -/// Optimize - Perform link time optimizations. This will run the scalar -/// optimizations, any loaded plugin-optimization modules, and then the -/// inter-procedural optimizations if applicable. -void Optimize(Module *M, llvm::ArrayRef<const char *> preservedFunctions) { - - // Instantiate the pass manager to organize the passes. - legacy::PassManager Passes; - - // If we're verifying, start off with a verification pass. - if (VerifyEach) - Passes.add(createVerifierPass()); - - // DWD - Run the opt standard pass list as well. - AddStandardCompilePasses(Passes); - - // Now that composite has been compiled, scan through the module, looking - // for a main function. If main is defined, mark all other functions - // internal. - if (!DisableInternalize) { - auto PreserveFunctions = [=](const GlobalValue &GV) { - StringRef GVName = GV.getName(); - - for (const char *fun : preservedFunctions) - if (GVName.equals(fun)) - return true; - - return false; - }; - ModulePass *pass = createInternalizePass(PreserveFunctions); - addPass(Passes, pass); - } - - // Propagate constants at call sites into the functions they call. This - // opens opportunities for globalopt (and inlining) by substituting function - // pointers passed as arguments to direct uses of functions. - addPass(Passes, createIPSCCPPass()); - - // Now that we internalized some globals, see if we can hack on them! - addPass(Passes, createGlobalOptimizerPass()); - - // Linking modules together can lead to duplicated global constants, only - // keep one copy of each constant... - addPass(Passes, createConstantMergePass()); - - // Remove unused arguments from functions... - addPass(Passes, createDeadArgEliminationPass()); - - // Reduce the code after globalopt and ipsccp. Both can open up significant - // simplification opportunities, and both can propagate functions through - // function pointers. When this happens, we often have to resolve varargs - // calls, etc, so let instcombine do this. - addPass(Passes, createInstructionCombiningPass()); - - if (!DisableInline) - addPass(Passes, createFunctionInliningPass()); // Inline small functions - - addPass(Passes, createPruneEHPass()); // Remove dead EH info - addPass(Passes, createGlobalOptimizerPass()); // Optimize globals again. - addPass(Passes, createGlobalDCEPass()); // Remove dead functions - - // If we didn't decide to inline a function, check to see if we can - // transform it to pass arguments by value instead of by reference. - addPass(Passes, createArgumentPromotionPass()); - - // The IPO passes may leave cruft around. Clean up after them. - addPass(Passes, createInstructionCombiningPass()); - addPass(Passes, createJumpThreadingPass()); // Thread jumps. - addPass(Passes, createSROAPass()); // Break up allocas - - // Run a few AA driven optimizations here and now, to cleanup the code. - addPass(Passes, createPostOrderFunctionAttrsLegacyPass()); - addPass(Passes, createReversePostOrderFunctionAttrsPass()); // Add nocapture - addPass(Passes, createGlobalsAAWrapperPass()); // IP alias analysis - - addPass(Passes, createLICMPass()); // Hoist loop invariants - addPass(Passes, createGVNPass()); // Remove redundancies - addPass(Passes, createMemCpyOptPass()); // Remove dead memcpy's - addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores - - // Cleanup and simplify the code after the scalar optimizations. - addPass(Passes, createInstructionCombiningPass()); - - addPass(Passes, createJumpThreadingPass()); // Thread jumps. - addPass(Passes, createPromoteMemoryToRegisterPass()); // Cleanup jumpthread. - - // Delete basic blocks, which optimization passes may have killed... - addPass(Passes, createCFGSimplificationPass()); - - // Now that we have optimized the program, discard unreachable functions... - addPass(Passes, createGlobalDCEPass()); - - // If the -s or -S command line options were specified, strip the symbols out - // of the resulting program to make it smaller. -s and -S are GNU ld options - // that we are supporting; they alias -strip-all and -strip-debug. - if (Strip || StripDebug) - addPass(Passes, createStripSymbolsPass(StripDebug && !Strip)); - - // The user's passes may leave cruft around; clean up after them. - addPass(Passes, createInstructionCombiningPass()); - addPass(Passes, createCFGSimplificationPass()); - addPass(Passes, createAggressiveDCEPass()); - addPass(Passes, createGlobalDCEPass()); - - // Run our queue of passes all at once now, efficiently. - Passes.run(*M); -} -} +using namespace klee; +void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + SwitchImplType SwitchType, std::string EntryPoint, + llvm::ArrayRef<const char *> preservedFunctions, + llvm::Module *module) { + assert(0); +} \ No newline at end of file diff --git a/lib/Module/OptimizeLegacy.cpp b/lib/Module/OptimizeLegacy.cpp new file mode 100644 index 00000000..53488924 --- /dev/null +++ b/lib/Module/OptimizeLegacy.cpp @@ -0,0 +1,249 @@ +// FIXME: This file is a bastard child of opt.cpp and llvm-ld's +// Optimize.cpp. This stuff should live in common code. + +//===- Optimize.cpp - Optimize a complete program -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements all optimization of the linked module for llvm-ld. +// +//===----------------------------------------------------------------------===// + +#include "klee/Config/Version.h" +#include "klee/Support/OptionCategories.h" + +#include "klee/Support/CompilerWarning.h" + +#include "ModuleHelper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/FunctionAttrs.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "llvm/Transforms/Utils.h" +DISABLE_WARNING_POP + +using namespace llvm; +using namespace klee; + +namespace { +static cl::opt<bool> + DisableInline("disable-inlining", + cl::desc("Do not run the inliner pass (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt<bool> DisableInternalize( + "disable-internalize", + cl::desc("Do not mark all symbols as internal (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt<bool> VerifyEach("verify-each", + cl::desc("Verify intermediate results of all " + "optimization passes (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt<bool> + Strip("strip-all", cl::desc("Strip all symbol information from executable"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt<bool> + StripDebug("strip-debug", + cl::desc("Strip debugger symbol info from executable"), + cl::init(false), cl::cat(klee::ModuleCat)); + +// A utility function that adds a pass to the pass manager but will also add +// a verifier pass after if we're supposed to verify. +static inline void addPass(legacy::PassManager &PM, Pass *P) { + // Add the pass to the pass manager... + PM.add(P); + + // If we are verifying all of the intermediate steps, add the verifier... + if (VerifyEach) + PM.add(createVerifierPass()); +} +} // namespace + +static void AddStandardCompilePasses(legacy::PassManager &PM) { + PM.add(createVerifierPass()); // Verify that input is correct + + // If the -strip-debug command line option was specified, do it. + if (StripDebug) + addPass(PM, createStripSymbolsPass(true)); + + addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code + addPass(PM, createPromoteMemoryToRegisterPass()); // Kill useless allocas + addPass(PM, createGlobalOptimizerPass()); // Optimize out global vars + addPass(PM, createGlobalDCEPass()); // Remove unused fns and globs +#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) + addPass(PM, createSCCPPass()); // Constant prop with SCCP +#else + addPass(PM, createIPConstantPropagationPass()); // IP Constant Propagation +#endif + addPass(PM, createDeadArgEliminationPass()); // Dead argument elimination + addPass(PM, createInstructionCombiningPass()); // Clean up after IPCP & DAE + addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE + + addPass(PM, createPruneEHPass()); // Remove dead EH info + addPass(PM, createPostOrderFunctionAttrsLegacyPass()); + addPass(PM, + createReversePostOrderFunctionAttrsPass()); // Deduce function attrs + + if (!DisableInline) + addPass(PM, createFunctionInliningPass()); // Inline small functions + addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args + + addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. + addPass(PM, createJumpThreadingPass()); // Thread jumps. + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createSROAPass()); // Break up aggregate allocas + addPass(PM, createInstructionCombiningPass()); // Combine silly seq's + + addPass(PM, createTailCallEliminationPass()); // Eliminate tail calls + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createReassociatePass()); // Reassociate expressions + addPass(PM, createLoopRotatePass()); + addPass(PM, createLICMPass()); // Hoist loop invariants + addPass(PM, createLoopUnswitchPass()); // Unswitch loops. + // FIXME : Removing instcombine causes nestedloop regression. + addPass(PM, createInstructionCombiningPass()); + addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars + addPass(PM, createLoopDeletionPass()); // Delete dead loops + addPass(PM, createLoopUnrollPass()); // Unroll small loops + addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller + addPass(PM, createGVNPass()); // Remove redundancies + addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset + addPass(PM, createSCCPPass()); // Constant prop with SCCP + + // Run instcombine after redundancy elimination to exploit opportunities + // opened up by them. + addPass(PM, createInstructionCombiningPass()); + + addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores + addPass(PM, createAggressiveDCEPass()); // Delete dead instructions + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createStripDeadPrototypesPass()); // Get rid of dead prototypes + addPass(PM, createConstantMergePass()); // Merge dup global constants +} + +/// Optimize - Perform link time optimizations. This will run the scalar +/// optimizations, any loaded plugin-optimization modules, and then the +/// inter-procedural optimizations if applicable. +void klee::optimizeModule(llvm::Module *M, + llvm::ArrayRef<const char *> preservedFunctions) { + + // Instantiate the pass manager to organize the passes. + legacy::PassManager Passes; + + // If we're verifying, start off with a verification pass. + if (VerifyEach) + Passes.add(createVerifierPass()); + + // DWD - Run the opt standard pass list as well. + AddStandardCompilePasses(Passes); + + // Now that composite has been compiled, scan through the module, looking + // for a main function. If main is defined, mark all other functions + // internal. + if (!DisableInternalize) { + auto PreserveFunctions = [=](const llvm::GlobalValue &GV) { + StringRef GVName = GV.getName(); + + for (const char *fun : preservedFunctions) + if (GVName.equals(fun)) + return true; + + return false; + }; + ModulePass *pass = createInternalizePass(PreserveFunctions); + addPass(Passes, pass); + } + + // Propagate constants at call sites into the functions they call. This + // opens opportunities for globalopt (and inlining) by substituting function + // pointers passed as arguments to direct uses of functions. + addPass(Passes, createIPSCCPPass()); + + // Now that we internalized some globals, see if we can hack on them! + addPass(Passes, createGlobalOptimizerPass()); + + // Linking modules together can lead to duplicated global constants, only + // keep one copy of each constant... + addPass(Passes, createConstantMergePass()); + + // Remove unused arguments from functions... + addPass(Passes, createDeadArgEliminationPass()); + + // Reduce the code after globalopt and ipsccp. Both can open up significant + // simplification opportunities, and both can propagate functions through + // function pointers. When this happens, we often have to resolve varargs + // calls, etc, so let instcombine do this. + addPass(Passes, createInstructionCombiningPass()); + + if (!DisableInline) + addPass(Passes, createFunctionInliningPass()); // Inline small functions + + addPass(Passes, createPruneEHPass()); // Remove dead EH info + addPass(Passes, createGlobalOptimizerPass()); // Optimize globals again. + addPass(Passes, createGlobalDCEPass()); // Remove dead functions + + // If we didn't decide to inline a function, check to see if we can + // transform it to pass arguments by value instead of by reference. + addPass(Passes, createArgumentPromotionPass()); + + // The IPO passes may leave cruft around. Clean up after them. + addPass(Passes, createInstructionCombiningPass()); + addPass(Passes, createJumpThreadingPass()); // Thread jumps. + addPass(Passes, createSROAPass()); // Break up allocas + + // Run a few AA driven optimizations here and now, to cleanup the code. + addPass(Passes, createPostOrderFunctionAttrsLegacyPass()); + addPass(Passes, createReversePostOrderFunctionAttrsPass()); // Add nocapture + addPass(Passes, createGlobalsAAWrapperPass()); // IP alias analysis + + addPass(Passes, createLICMPass()); // Hoist loop invariants + addPass(Passes, createGVNPass()); // Remove redundancies + addPass(Passes, createMemCpyOptPass()); // Remove dead memcpy's + addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores + + // Cleanup and simplify the code after the scalar optimizations. + addPass(Passes, createInstructionCombiningPass()); + + addPass(Passes, createJumpThreadingPass()); // Thread jumps. + addPass(Passes, createPromoteMemoryToRegisterPass()); // Cleanup jumpthread. + + // Delete basic blocks, which optimization passes may have killed... + addPass(Passes, createCFGSimplificationPass()); + + // Now that we have optimized the program, discard unreachable functions... + addPass(Passes, createGlobalDCEPass()); + + // If the -s or -S command line options were specified, strip the symbols out + // of the resulting program to make it smaller. -s and -S are GNU ld options + // that we are supporting; they alias -strip-all and -strip-debug. + if (Strip || StripDebug) + addPass(Passes, createStripSymbolsPass(StripDebug && !Strip)); + + // The user's passes may leave cruft around; clean up after them. + addPass(Passes, createInstructionCombiningPass()); + addPass(Passes, createCFGSimplificationPass()); + addPass(Passes, createAggressiveDCEPass()); + addPass(Passes, createGlobalDCEPass()); + + // Run our queue of passes all at once now, efficiently. + Passes.run(*M); +} |