| //===-- sc - SAFECode Compiler Tool ---------------------------------------===// |
| // |
| // The SAFECode Project |
| // |
| // This file was developed by the LLVM research group and is distributed |
| // under the University of Illinois Open Source License. See LICENSE.TXT for |
| // details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This program is a tool to run the SAFECode passes on a bytecode input file. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "safecode/SAFECode.h" |
| #include "safecode/SAFECodeConfig.h" |
| #include "safecode/InsertChecks/RegisterBounds.h" |
| #include "safecode/InsertChecks/RegisterRuntimeInitializer.h" |
| #include "safecode/Support/AllocatorInfo.h" |
| |
| #include "llvm/Module.h" |
| #include "llvm/LLVMContext.h" |
| #include "llvm/Bitcode/ReaderWriter.h" |
| #include "llvm/PassManager.h" |
| #include "llvm/Pass.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/PluginLoader.h" |
| #include "llvm/Support/FileUtilities.h" |
| #include "llvm/Support/ManagedStatic.h" |
| #include "llvm/Target/TargetData.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Transforms/IPO.h" |
| #include "llvm/Transforms/Scalar.h" |
| #include "llvm/Analysis/Verifier.h" |
| #include "llvm/System/Signals.h" |
| #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" |
| |
| #include "poolalloc/PoolAllocate.h" |
| |
| #include "ABCPreProcess.h" |
| #include "InsertPoolChecks.h" |
| #include "IndirectCallChecks.h" |
| #include "safecode/BreakConstantGEPs.h" |
| #include "safecode/BreakConstantStrings.h" |
| #include "safecode/CStdLib.h" |
| #include "safecode/DebugInstrumentation.h" |
| #include "safecode/DetectDanglingPointers.h" |
| #include "safecode/DummyUse.h" |
| #include "safecode/OptimizeChecks.h" |
| #include "safecode/RewriteOOB.h" |
| #include "safecode/SpeculativeChecking.h" |
| #include "safecode/LowerSafecodeIntrinsic.h" |
| #include "safecode/FaultInjector.h" |
| #include "safecode/CodeDuplication.h" |
| |
| #include <fstream> |
| #include <iostream> |
| #include <memory> |
| |
| namespace llvm { |
| extern ModulePass * createSteensgaardPass(); |
| } |
| |
| using namespace llvm; |
| using namespace NAMESPACE_SC; |
| |
| // General options for sc. |
| static cl::opt<std::string> |
| InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-")); |
| |
| static cl::opt<std::string> |
| OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); |
| |
| static cl::opt<bool> |
| Force("f", cl::desc("Overwrite output files")); |
| |
| static cl::opt<bool> |
| DisableDebugInfo("disable-debuginfo", cl::init(false), |
| cl::desc("Disable Debugging Info in Run-time Errors")); |
| |
| static cl::opt<bool> |
| DisableCStdLib("disable-cstdlib", cl::init(true), cl::desc("Disable transformations that secure C standard library calls")); |
| |
| static cl::opt<bool> |
| EnableFastCallChecks("enable-fastcallchecks", cl::init(false), |
| cl::desc("Enable fast indirect call checks")); |
| |
| static cl::opt<bool> |
| DisableMonotonicLoopOpt("disable-monotonic-loop-opt", cl::init(false), cl::desc("Disable optimization for checking monotonic loops")); |
| |
| enum CheckingRuntimeType { |
| RUNTIME_PA, RUNTIME_DEBUG, RUNTIME_SINGLETHREAD, RUNTIME_PARALLEL, RUNTIME_QUEUE_OP, RUNTIME_SVA |
| }; |
| |
| enum CheckingRuntimeType DefaultRuntime = RUNTIME_DEBUG; |
| |
| static cl::opt<enum CheckingRuntimeType> |
| CheckingRuntime("runtime", cl::init(DefaultRuntime), |
| cl::desc("The runtime API used by the program"), |
| cl::values( |
| clEnumVal(RUNTIME_PA, "Pool Allocation runtime no checks)"), |
| clEnumVal(RUNTIME_DEBUG, "Debugging Tool runtime"), |
| clEnumVal(RUNTIME_SINGLETHREAD, "Single Thread runtime (Production version)"), |
| clEnumVal(RUNTIME_PARALLEL, "Parallel Checking runtime (Production version)"), |
| clEnumVal(RUNTIME_QUEUE_OP, "Parallel no-op Checking runtime (For testing queue performance)"), |
| clEnumVal(RUNTIME_SVA, "Runtime for SVA"), |
| clEnumValEnd)); |
| |
| static cl::opt<bool> |
| EnableProtectingMetaData("protect-metadata", cl::init(false), |
| cl::desc("Instrument store instructions to protect the meta data")); |
| |
| static cl::opt<bool> |
| EnableCodeDuplication("code-duplication", cl::init(false), |
| cl::desc("Enable Code Duplication for SAFECode checking")); |
| |
| #define NOT_FOR_SVA(X) do { if (!SCConfig.svaEnabled()) X; } while (0); |
| |
| static void addLowerIntrinsicPass(PassManager & Passes, CheckingRuntimeType type); |
| static void addStaticGEPCheckingPass(PassManager & Passes); |
| static void addPoolAllocationPass(PassManager & Passes); |
| |
| // GetFileNameRoot - Helper function to get the basename of a filename. |
| static inline std::string |
| GetFileNameRoot(const std::string &InputFilename) { |
| std::string IFN = InputFilename; |
| std::string outputFilename; |
| int Len = IFN.length(); |
| if ((Len > 2) && |
| IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') { |
| outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/ |
| } else { |
| outputFilename = IFN; |
| } |
| return outputFilename; |
| } |
| |
| // AllocatorInfo |
| namespace { |
| // vmalloc |
| SimpleAllocatorInfo AllocatorVMalloc("vmalloc", "vfree", 1, 1); |
| // kmalloc |
| SimpleAllocatorInfo AllocatorKMalloc("__kmalloc", "kfree", 1, 1); |
| // __alloc_bootmem |
| SimpleAllocatorInfo AllocatorBootmem("__alloc_bootmem", "", 1, 1); |
| // pool allocator used by user space programs |
| SimpleAllocatorInfo AllocatorPoolAlloc("poolalloc", "poolfree", 2, 2); |
| } |
| |
| |
| // main - Entry point for the sc compiler. |
| // |
| int main(int argc, char **argv) { |
| std::string mt; |
| std::string & msg = mt; |
| LLVMContext &Context = getGlobalContext(); |
| llvm_shutdown_obj ShutdownObject; |
| |
| try { |
| cl::ParseCommandLineOptions(argc, argv, "SAFECode Compiler\n"); |
| sys::PrintStackTraceOnErrorSignal(); |
| |
| // Load the module to be compiled... |
| std::auto_ptr<Module> M; |
| std::string ErrorMessage; |
| if (MemoryBuffer *Buffer |
| = MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)) { |
| M.reset(ParseBitcodeFile(Buffer, Context, &ErrorMessage)); |
| delete Buffer; |
| } |
| |
| if (M.get() == 0) { |
| std::cerr << argv[0] << ": bytecode didn't read correctly.\n"; |
| return 1; |
| } |
| |
| // The type of DSA depends on which pool allocation pass is used. |
| if (SCConfig.svaEnabled()) { |
| SCConfig.allocators.push_back(&AllocatorVMalloc); |
| SCConfig.allocators.push_back(&AllocatorKMalloc); |
| SCConfig.allocators.push_back(&AllocatorBootmem); |
| } else { |
| SCConfig.allocators.push_back(&AllocatorPoolAlloc); |
| } |
| |
| // Build up all of the passes that we want to do to the module... |
| PassManager Passes; |
| Passes.add(new TargetData(M.get())); |
| |
| // |
| // Merge constants. We do this here because merging constants *after* |
| // running SAFECode may cause incorrect registration of global objects |
| // (e.g., two global object registrations may register the same object |
| // because the globals are identical constant strings). |
| // |
| Passes.add (createConstantMergePass()); |
| |
| // Remove all constant GEP expressions |
| NOT_FOR_SVA(Passes.add(new BreakConstantGEPs())); |
| |
| // Ensure that all malloc/free calls are changed into LLVM instructions |
| NOT_FOR_SVA(Passes.add(createRaiseAllocationsPass())); |
| |
| // |
| // Remove indirect calls to malloc and free functions. This can be done |
| // here because none of the SAFECode transforms will add indirect calls to |
| // malloc() and free(). |
| // |
| NOT_FOR_SVA(Passes.add(createIndMemRemPass())); |
| |
| // Ensure that all malloc/free calls are changed into LLVM instructions |
| NOT_FOR_SVA(Passes.add(createRaiseAllocationsPass())); |
| |
| // |
| // Ensure that all functions have only a single return instruction. We do |
| // this to make stack-to-heap promotion easier (with a single return |
| // instruction, we know where to free all of the promoted alloca's). |
| // |
| NOT_FOR_SVA(Passes.add(createUnifyFunctionExitNodesPass())); |
| |
| // |
| // Convert Unsafe alloc instructions first. This does not rely upon |
| // pool allocation and has problems dealing with cloned functions. |
| // |
| if (CheckingRuntime != RUNTIME_PA) { |
| Passes.add(new ArrayBoundsCheckLocal()); |
| NOT_FOR_SVA(Passes.add(new ConvertUnsafeAllocas())); |
| } |
| |
| #if 0 |
| // Schedule the Bottom-Up Call Graph analysis before pool allocation. The |
| // Bottom-Up Call Graph pass doesn't work after pool allocation has |
| // been run, and PassManager schedules it after pool allocation for |
| // some reason. |
| NOT_FOR_SVA(Passes.add(new BottomUpCallGraph())); |
| |
| NOT_FOR_SVA(Passes.add(new ParCheckingCallAnalysis())); |
| #endif |
| |
| // |
| // Run pool allocation. |
| // |
| addPoolAllocationPass(Passes); |
| |
| #if 0 |
| // Convert Unsafe alloc instructions first. This version relies upon |
| // pool allocation, |
| Passes.add(new PAConvertUnsafeAllocas()); |
| #endif |
| |
| // |
| // Disable this pass for now. We don't really use it, and it generates |
| // lots of compiler warnings. |
| // |
| #if 0 |
| Passes.add(new EmbeCFreeRemoval()); |
| #endif |
| |
| // |
| // Instrument the code so that memory objects are registered into the |
| // correct pools. Note that user-space SAFECode requires a few additional |
| // transforms to do this. |
| // |
| Passes.add(new RegisterGlobalVariables()); |
| |
| if (!SCConfig.svaEnabled()) { |
| Passes.add(new RegisterMainArgs()); |
| Passes.add(new RegisterRuntimeInitializer()); |
| } |
| |
| Passes.add(new RegisterFunctionByvalArguments()); |
| |
| // Register all customized allocators, such as vmalloc() / kmalloc() in |
| // kernel, or poolalloc() in pool allocation |
| Passes.add(new RegisterCustomizedAllocation()); |
| |
| // |
| // Use static analysis to determine which indexing operations (GEPs) do not |
| // require run-time checks. This is scheduled right before the check |
| // insertion pass because it seems that the PassManager will invalidate the |
| // results if they are not consumed immediently. |
| // |
| addStaticGEPCheckingPass(Passes); |
| |
| Passes.add(new InsertPoolChecks()); |
| |
| Passes.add(new ExactCheckOpt()); |
| |
| NOT_FOR_SVA(Passes.add(new RegisterStackObjPass())); |
| NOT_FOR_SVA(Passes.add(new InitAllocas())); |
| |
| if (EnableFastCallChecks) |
| Passes.add(createIndirectCallChecksPass()); |
| |
| if (!DisableCStdLib) { |
| NOT_FOR_SVA(Passes.add(new StringTransform())); |
| } |
| |
| if (!DisableMonotonicLoopOpt) |
| Passes.add(new MonotonicLoopOpt()); |
| |
| if (CheckingRuntime == RUNTIME_PARALLEL) { |
| Passes.add(new SpeculativeCheckingInsertSyncPoints()); |
| |
| if (EnableProtectingMetaData) { |
| Passes.add(new SpeculativeCheckStoreCheckPass()); |
| } |
| } |
| |
| // |
| // Do post processing required for Out of Bounds pointer rewriting. |
| // Note that the RewriteOOB pass is always required for user-space |
| // SAFECode because it is how we handle the C standard allowing pointers to |
| // move one beyond the end of an object as long as the pointer is not |
| // dereferenced. |
| // |
| // Try to optimize the checks first as the RewriteOOB pass may make |
| // optimization impossible. |
| // |
| if (CheckingRuntime == RUNTIME_DEBUG) { |
| Passes.add (new OptimizeChecks()); |
| Passes.add(new RewriteOOB()); |
| } |
| |
| Passes.add (new DummyUse()); |
| |
| #if 0 |
| // |
| // Run the LICM pass to hoist checks out of loops. |
| // |
| Passes.add (createLICMPass()); |
| #endif |
| |
| // |
| // Remove special attributes for loop hoisting that were added by previous |
| // SAFECode passes. |
| // |
| Passes.add (createClearCheckAttributesPass()); |
| |
| if (EnableCodeDuplication) |
| Passes.add(new DuplicateLoopAnalysis()); |
| |
| // |
| // Attempt to optimize the checks. Do not optimize object registration |
| // in debug mode because we need to use pool_unregister to detect invalid |
| // frees. |
| // |
| Passes.add (new OptimizeChecks()); |
| if (DisableDebugInfo) { |
| Passes.add (new PoolRegisterElimination()); |
| } else { |
| Passes.add (new DebugPoolRegisterElimination()); |
| } |
| |
| Passes.add(new UnusedCheckElimination()); |
| |
| // |
| // Instrument the code so that dangling pointers are detected. |
| // |
| Passes.add(new DetectDanglingPointers()); |
| |
| if (!DisableDebugInfo) |
| Passes.add (new DebugInstrument()); |
| |
| // Lower the checking intrinsics into appropriate runtime function calls. |
| // It should be the last pass |
| addLowerIntrinsicPass(Passes, CheckingRuntime); |
| |
| // Make all strings non-constant so that the linker doesn't try to merge |
| // them together. |
| Passes.add(new BreakConstantStrings()); |
| |
| // Verify the final result |
| Passes.add(createVerifierPass()); |
| |
| // Figure out where we are going to send the output... |
| std::ostream *Out = 0; |
| if (OutputFilename != "") { |
| if (OutputFilename != "-") { |
| // Specified an output filename? |
| if (!Force && std::ifstream(OutputFilename.c_str())) { |
| // If force is not specified, make sure not to overwrite a file! |
| std::cerr << argv[0] << ": error opening '" << OutputFilename |
| << "': file exists!\n" |
| << "Use -f command line argument to force output\n"; |
| return 1; |
| } |
| Out = new std::ofstream(OutputFilename.c_str()); |
| |
| // Make sure that the Out file gets unlinked from the disk if we get a |
| // SIGINT |
| sys::RemoveFileOnSignal(sys::Path(OutputFilename)); |
| } else { |
| Out = &std::cout; |
| } |
| } else { |
| if (InputFilename == "-") { |
| OutputFilename = "-"; |
| Out = &std::cout; |
| } else { |
| OutputFilename = GetFileNameRoot(InputFilename); |
| |
| OutputFilename += ".sc.bc"; |
| } |
| |
| if (!Force && std::ifstream(OutputFilename.c_str())) { |
| // If force is not specified, make sure not to overwrite a file! |
| std::cerr << argv[0] << ": error opening '" << OutputFilename |
| << "': file exists!\n" |
| << "Use -f command line argument to force output\n"; |
| return 1; |
| } |
| |
| Out = new std::ofstream(OutputFilename.c_str()); |
| if (!Out->good()) { |
| std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; |
| delete Out; |
| return 1; |
| } |
| |
| // Make sure that the Out file gets unlinked from the disk if we get a |
| // SIGINT |
| sys::RemoveFileOnSignal(sys::Path(OutputFilename)); |
| } |
| |
| // Add the writing of the output file to the list of passes |
| Passes.add (CreateBitcodeWriterPass(*Out)); |
| |
| // Run our queue of passes all at once now, efficiently. |
| Passes.run(*M.get()); |
| |
| // Delete the ostream if it's not a stdout stream |
| if (Out != &std::cout) delete Out; |
| |
| return 0; |
| } catch (msg) { |
| std::cerr << argv[0] << ": " << msg << "\n"; |
| } catch (...) { |
| std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n"; |
| } |
| llvm_shutdown(); |
| return 1; |
| } |
| |
| static void addStaticGEPCheckingPass(PassManager & Passes) { |
| switch (SCConfig.staticCheckType()) { |
| case SAFECodeConfiguration::ABC_CHECK_NONE: |
| Passes.add(new ArrayBoundsCheckDummy()); |
| break; |
| case SAFECodeConfiguration::ABC_CHECK_LOCAL: |
| Passes.add(new ArrayBoundsCheckStruct()); |
| Passes.add(new ArrayBoundsCheckLocal()); |
| break; |
| case SAFECodeConfiguration::ABC_CHECK_FULL: |
| #if 0 |
| Passes.add(new ABCPreProcess()); |
| Passes.add(new ArrayBoundsCheckStruct()); |
| Passes.add(new ArrayBoundsCheck()); |
| #else |
| assert (0 && "Omega pass is not working right now!"); |
| #endif |
| break; |
| } |
| } |
| |
| static void addLowerIntrinsicPass(PassManager & Passes, CheckingRuntimeType type) { |
| /// Mapping between check intrinsics and implementation |
| |
| typedef LowerSafecodeIntrinsic::IntrinsicMappingEntry IntrinsicMappingEntry; |
| static IntrinsicMappingEntry RuntimePA[] = |
| { {"sc.lscheck", "__sc_no_op_poolcheck" }, |
| {"sc.lscheckui", "__sc_no_op_poolcheck" }, |
| {"sc.lscheckalign", "__sc_no_op_poolcheckalign" }, |
| {"sc.lscheckalignui", "__sc_no_op_poolcheckalign" }, |
| {"sc.boundscheck", "__sc_no_op_boundscheck" }, |
| {"sc.boundscheckui", "__sc_no_op_boundscheck" }, |
| {"sc.exactcheck", "__sc_no_op_exactcheck" }, |
| {"sc.exactcheck2", "__sc_no_op_exactcheck2" }, |
| {"poolregister", "__sc_no_op_poolregister" }, |
| {"poolunregister", "__sc_no_op_poolunregister" }, |
| {"poolalloc", "__sc_barebone_poolalloc"}, |
| {"poolfree", "__sc_barebone_poolfree"}, |
| {"pooldestroy", "__sc_barebone_pooldestroy"}, |
| {"pool_init_runtime", "__sc_barebone_pool_init_runtime"}, |
| {"poolinit", "__sc_barebone_poolinit"}, |
| {"poolrealloc", "__sc_barebone_poolrealloc"}, |
| {"poolcalloc", "__sc_barebone_poolcalloc"}, |
| {"poolstrdup", "__sc_barebone_poolstrdup"}, |
| {"sc.get_actual_val", "pchk_getActualValue" }, |
| }; |
| |
| static IntrinsicMappingEntry RuntimeSingleThread[] = |
| { {"sc.lscheck", "sc.lscheck" }, |
| {"sc.lscheckui", "__sc_no_op_poolcheck" }, |
| {"sc.lscheckalign", "poolcheckalign" }, |
| {"sc.lscheckalignui", "poolcheckalignui" }, |
| {"sc.boundscheck", "boundscheck" }, |
| {"sc.boundscheckui", "boundscheckui" }, |
| {"sc.exactcheck", "exactcheck" }, |
| {"sc.exactcheck2", "exactcheck2" }, |
| {"sc.pool_register", "poolregister" }, |
| {"sc.pool_unregister", "poolunregister" }, |
| {"sc.init_pool_runtime", "__sc_bc_pool_init_runtime"}, |
| {"poolalloc", "__sc_bc_poolalloc"}, |
| {"poolfree", "__sc_bc_poolfree"}, |
| {"pooldestroy", "__sc_bc_pooldestroy"}, |
| {"poolinit", "__sc_bc_poolinit"}, |
| {"poolrealloc", "__sc_bc_poolrealloc"}, |
| {"poolcalloc", "__sc_bc_poolcalloc"}, |
| {"poolstrdup", "__sc_bc_poolstrdup"}, |
| {"sc.get_actual_val", "pchk_getActualValue" }, |
| }; |
| |
| static IntrinsicMappingEntry RuntimeDebug[] = |
| { {"sc.lscheck", "poolcheck" }, |
| {"sc.lscheckui", "poolcheckui" }, |
| {"sc.lscheckalign", "poolcheckalign" }, |
| {"sc.lscheckalignui", "poolcheckalignui" }, |
| {"sc.boundscheck", "boundscheck" }, |
| {"sc.boundscheckui", "boundscheckui" }, |
| {"sc.exactcheck", "exactcheck" }, |
| {"sc.exactcheck2", "exactcheck2" }, |
| {"sc.funccheck", "__sc_dbg_funccheck" }, |
| {"sc.get_actual_val", "pchk_getActualValue" }, |
| {"sc.pool_register", "__sc_dbg_poolregister" }, |
| {"sc.pool_unregister", "__sc_dbg_poolunregister" }, |
| {"sc.pool_unregister_stack", "__sc_dbg_poolunregister_stack" }, |
| {"sc.pool_unregister_debug", "__sc_dbg_poolunregister_debug" }, |
| {"sc.pool_unregister_stack_debug", "__sc_dbg_poolunregister_stack_debug" }, |
| {"poolalloc", "__pa_bitmap_poolalloc"}, |
| |
| {"sc.init_pool_runtime", "pool_init_runtime"}, |
| {"sc.pool_register_debug", "__sc_dbg_src_poolregister"}, |
| {"sc.pool_register_stack_debug", "__sc_dbg_src_poolregister_stack"}, |
| {"sc.pool_register_stack", "__sc_dbg_poolregister_stack"}, |
| {"sc.pool_register_global", "__sc_dbg_poolregister_global"}, |
| {"sc.pool_register_global_debug", "__sc_dbg_poolregister_global_debug"}, |
| {"sc.lscheck_debug", "poolcheck_debug"}, |
| {"sc.lscheckalign_debug", "poolcheckalign_debug"}, |
| {"sc.boundscheck_debug", "boundscheck_debug"}, |
| {"sc.boundscheckui_debug","boundscheckui_debug"}, |
| {"sc.exactcheck2_debug", "exactcheck2_debug"}, |
| {"sc.pool_argvregister", "__sc_dbg_poolargvregister"}, |
| |
| {"poolinit", "__sc_dbg_poolinit"}, |
| {"poolalloc_debug", "__sc_dbg_src_poolalloc"}, |
| {"poolfree_debug", "__sc_dbg_src_poolfree"}, |
| |
| // These functions register objects in the splay trees |
| {"poolcalloc_debug", "__sc_dbg_src_poolcalloc"}, |
| {"poolcalloc", "__sc_dbg_poolcalloc"}, |
| {"poolstrdup", "__sc_dbg_poolstrdup"}, |
| {"poolstrdup_debug", "__sc_dbg_poolstrdup_debug"}, |
| {"poolrealloc", "__sc_dbg_poolrealloc"}, |
| }; |
| |
| |
| static IntrinsicMappingEntry RuntimeParallel[] = |
| { {"sc.lscheck", "__sc_par_poolcheck" }, |
| {"sc.lscheckui", "__sc_no_op_poolcheck" }, |
| {"sc.lscheckalign", "__sc_par_poolcheckalign" }, |
| {"sc.lscheckalignui", "__sc_par_poolcheckalignui" }, |
| {"sc.boundscheck", "__sc_par_boundscheck" }, |
| {"sc.boundscheckui", "__sc_par_boundscheckui" }, |
| {"sc.exactcheck", "exactcheck" }, |
| {"sc.exactcheck2", "exactcheck2" }, |
| {"sc.lscheck.serial", "__sc_bc_poolcheck" }, |
| {"sc.lscheckui.serial", "__sc_no_op_poolcheck" }, |
| {"sc.lscheckalign.serial","poolcheckalign" }, |
| {"sc.lscheckalignui.serial","poolcheckalignui" }, |
| {"sc.boundscheck.serial", "__sc_bc_boundscheck" }, |
| {"sc.boundscheckui.serial", "__sc_bc_boundscheckui" }, |
| {"sc.exactcheck.serial", "exactcheck" }, |
| {"sc.exactcheck2.serial", "exactcheck2" }, |
| {"poolargvregister", "__sc_par_poolargvregister" }, |
| {"poolregister", "__sc_par_poolregister" }, |
| {"poolunregister", "__sc_par_poolunregister" }, |
| {"poolalloc", "__sc_par_poolalloc"}, |
| {"poolfree", "__sc_par_poolfree"}, |
| {"pooldestroy", "__sc_par_pooldestroy"}, |
| {"pool_init_runtime", "__sc_par_pool_init_runtime"}, |
| {"poolinit", "__sc_par_poolinit"}, |
| {"poolrealloc", "__sc_par_poolrealloc"}, |
| {"poolcalloc", "__sc_par_poolcalloc"}, |
| {"poolstrdup", "__sc_par_poolstrdup"}, |
| }; |
| |
| const char * queueOpFunction = "__sc_par_enqueue_1"; |
| |
| static IntrinsicMappingEntry RuntimeQueuePerformance[] = |
| { {"sc.lscheck", queueOpFunction}, |
| {"sc.lscheckui", queueOpFunction}, |
| {"sc.lscheckalign", queueOpFunction}, |
| {"sc.lscheckalignui", queueOpFunction}, |
| {"sc.boundscheck", queueOpFunction}, |
| {"sc.boundscheckui", queueOpFunction}, |
| {"sc.exactcheck", "exactcheck" }, |
| {"sc.exactcheck2", "exactcheck2" }, |
| {"poolregister", queueOpFunction}, |
| {"poolunregister", queueOpFunction}, |
| {"poolalloc", "__sc_barebone_poolalloc"}, |
| {"poolfree", "__sc_barebone_poolfree"}, |
| {"pooldestroy", "__sc_barebone_pooldestroy"}, |
| {"pool_init_runtime", "__sc_par_pool_init_runtime"}, |
| {"poolinit", "__sc_barebone_poolinit"}, |
| {"poolrealloc", "__sc_barebone_poolrealloc"}, |
| {"poolcalloc", "__sc_barebone_poolcalloc"}, |
| {"poolstrdup", "__sc_barebone_poolstrdup"}, |
| }; |
| |
| static IntrinsicMappingEntry RuntimeSVA[] = |
| { {"sc.lscheck", "poolcheck" }, |
| {"sc.lscheckui", "poolcheck_i" }, |
| {"sc.lscheckalign", "poolcheckalign" }, |
| {"sc.lscheckalignui", "poolcheckalign_i" }, |
| {"sc.boundscheck", "pchk_bounds" }, |
| {"sc.boundscheckui", "pchk_bounds_i" }, |
| {"sc.exactcheck", "exactcheck" }, |
| {"sc.exactcheck2", "exactcheck2" }, |
| {"sc.pool_register", "pchk_reg_obj" }, |
| {"sc.pool_unregister", "pchk_drop_obj" }, |
| {"poolinit", "__sva_pool_init" }, |
| }; |
| |
| switch (type) { |
| case RUNTIME_PA: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimePA, RuntimePA + sizeof(RuntimePA) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| case RUNTIME_DEBUG: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimeDebug, RuntimeDebug + sizeof(RuntimeDebug) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| case RUNTIME_SINGLETHREAD: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimeSingleThread, RuntimeSingleThread + sizeof(RuntimeSingleThread) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| case RUNTIME_PARALLEL: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimeParallel, RuntimeParallel + sizeof(RuntimeParallel) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| case RUNTIME_QUEUE_OP: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimeQueuePerformance, RuntimeQueuePerformance+ sizeof(RuntimeQueuePerformance) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| case RUNTIME_SVA: |
| Passes.add(new LowerSafecodeIntrinsic(RuntimeSVA, RuntimeSVA + sizeof(RuntimeSVA) / sizeof(IntrinsicMappingEntry))); |
| break; |
| |
| default: |
| assert (0 && "Invalid Runtime!"); |
| } |
| } |
| |
| static void addPoolAllocationPass(PassManager & Passes) { |
| switch (SCConfig.getPAType()) { |
| case SAFECodeConfiguration::PA_SINGLE: |
| Passes.add(new PoolAllocateSimple(true, true, false)); |
| break; |
| case SAFECodeConfiguration::PA_SIMPLE: |
| Passes.add(new PoolAllocateSimple(true, true, true)); |
| break; |
| case SAFECodeConfiguration::PA_MULTI: |
| Passes.add(new PoolAllocateMultipleGlobalPool()); |
| break; |
| case SAFECodeConfiguration::PA_APA: |
| Passes.add(new PoolAllocate(true, true)); |
| break; |
| } |
| } |