#include "JIT_Compiler.hpp" #include #include #include //using namespace std; //using namespace llvm; #include #include #include #include #include #include #include #include #include "PassPrinters.hh" #define FREE_ALLOCATED() \ free(buffer); \ free(p->y_u.J.jh->cmd); \ free(outputfilename); \ free(optoutputfilename); \ free(cmd1); \ free(cmd2); #define ADD_PASS_ACCORDING_TO_KIND() \ switch (Kind) { \ case PT_BasicBlock: \ fprintf(stderr, "Oops -- basicblock printer\n"); \ exit(1); \ case PT_Region: \ Pass.add(new RegionPassPrinter(PInfo)); \ break; \ case PT_Loop: \ Pass.add(new LoopPassPrinter(PInfo)); \ break; \ case PT_Function: \ Pass.add(new FunctionPassPrinter(PInfo)); \ break; \ case PT_CallGraphSCC: \ Pass.add(new CallGraphSCCPassPrinter(PInfo)); \ break; \ default: \ Pass.add(new ModulePassPrinter(PInfo)); \ break; \ } #define TREAT_CASE_FOR(PASS) \ PInfo = PassRegistry::getPassRegistry()->getPassInfo(PASS->getPassID()); \ Kind = PASS->getPassKind(); \ ADD_PASS_ACCORDING_TO_KIND(); void JIT_Compiler::analyze_module(llvm::Module* &M) { PassManager Pass; // 'Pass' stores analysis passes to be applied TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple())); const PassInfo *PInfo; PassKind Kind; Pass.add(TLI); // First, I add on 'Pass' the Target Info of Module Pass.add(new DataLayoutPass()); // Second, I must add Target Data on 'Pass' for (int i = 0; i < ExpEnv.analysis_struc.n; i++) { /* * 'ExpEnv.analysis_struc.act_an' contains sorted analysis passes * * 'ExpEnv.analysis_struc.act_an' is filled by analysis predicates * * What must I do? * * 1. Pass over 'ExpEnv.analysis_struc.act_an' (by previous 'for') * * 2. For each unity within 'ExpEnv.analysis_struc.act_an' * * 2.1. Check its type * * 2.2. Add analysis pass on 'Pass' accordingly the type checked * */ switch (ExpEnv.analysis_struc.act_an[i]) { case e_createAAEvalPass: TREAT_CASE_FOR(createAAEvalPass()); break; case e_createBasicAliasAnalysisPass: TREAT_CASE_FOR(createBasicAliasAnalysisPass()); break; case e_createAliasAnalysisCounterPass: TREAT_CASE_FOR(createAliasAnalysisCounterPass()); break; case e_createGlobalsModRefPass: TREAT_CASE_FOR(createGlobalsModRefPass()); break; case e_createInstCountPass: TREAT_CASE_FOR(createInstCountPass()); break; case e_createIVUsersPass: TREAT_CASE_FOR(createIVUsersPass()); break; case e_createLazyValueInfoPass: TREAT_CASE_FOR(createLazyValueInfoPass()); break; //CHANGED FOR LLVM 3.5 case e_createLoopDependenceAnalysisPass: TREAT_CASE_FOR(createDependenceAnalysisPass()); break; case e_createLibCallAliasAnalysisPass: TREAT_CASE_FOR(createLibCallAliasAnalysisPass(NULL)); break; case e_createLintPass: TREAT_CASE_FOR(createLintPass()); break; case e_createMemDepPrinter: TREAT_CASE_FOR(createMemDepPrinter()); break; case e_createModuleDebugInfoPrinterPass: TREAT_CASE_FOR(createModuleDebugInfoPrinterPass()); break; case e_createNoAAPass: TREAT_CASE_FOR(createNoAAPass()); break; //NOT IN LLVM 3.5 //case e_createNoPathProfileInfoPass: // TREAT_CASE_FOR(createNoPathProfileInfoPass()); // break; //NOT IN LLVM 3.5 //case e_createNoProfileInfoPass: // TREAT_CASE_FOR(createNoProfileInfoPass()); // break; case e_createObjCARCAliasAnalysisPass: TREAT_CASE_FOR(createObjCARCAliasAnalysisPass()); break; //NOT IN LLVM 3.5 //case e_createProfileEstimatorPass: // TREAT_CASE_FOR(createProfileEstimatorPass()); // break; //CHANGED FOR LLVM 3.5 case e_createProfileLoaderPass: TREAT_CASE_FOR(createSampleProfileLoaderPass()); break; //NOT IN LLVM 3.5 //case e_createProfileVerifierPass: // TREAT_CASE_FOR(createProfileVerifierPass()); // break; case e_createRegionInfoPass: TREAT_CASE_FOR(createRegionInfoPass()); break; case e_createScalarEvolutionAliasAnalysisPass: TREAT_CASE_FOR(createScalarEvolutionAliasAnalysisPass()); break; case e_createTypeBasedAliasAnalysisPass: TREAT_CASE_FOR(createTypeBasedAliasAnalysisPass()); break; //CHANGED FOR LLVM 3.5 case e_createDbgInfoPrinterPass: TREAT_CASE_FOR(createDebugInfoVerifierPass()); break; case e_createCFGPrinterPass: TREAT_CASE_FOR(createCFGPrinterPass()); break; case e_createCFGOnlyPrinterPass: TREAT_CASE_FOR(createCFGOnlyPrinterPass()); break; case e_createDomPrinterPass: TREAT_CASE_FOR(createDomPrinterPass()); break; case e_createDomOnlyPrinterPass: TREAT_CASE_FOR(createDomOnlyPrinterPass()); break; case e_createPostDomPrinterPass: TREAT_CASE_FOR(createPostDomPrinterPass()); break; case e_createPostDomOnlyPrinterPass: TREAT_CASE_FOR(createPostDomOnlyPrinterPass()); break; case e_createRegionPrinterPass: TREAT_CASE_FOR(createRegionPrinterPass()); break; case e_createRegionOnlyPrinterPass: TREAT_CASE_FOR(createRegionOnlyPrinterPass()); break; //NOT IN LLVM 3.5 //case e_createPathProfileLoaderPass: // TREAT_CASE_FOR(createPathProfileLoaderPass()); // break; //NOT IN LLVM 3.5 //case e_createPathProfileVerifierPass: // TREAT_CASE_FOR(createPathProfileVerifierPass()); // break; default:; } } /* if 'llvm::TimePassesIsEnabled' is 'true', llvm time passes are printed on 'shutdown_llvm()' (p_halt -- stdpreds.c) */ llvm::TimePassesIsEnabled = ExpEnv.analysis_struc.time_pass_enabled; /* Use 'llvm::EnableStatistics()' so that llvm stats are printed on 'shutdown_llvm()' (p_halt -- stdpreds.c) */ if (ExpEnv.analysis_struc.stats_enabled) llvm::EnableStatistics(); /* * Here, I configure resulting analysis output -- default: stderr * * Use analysis_output_file/1 to change * */ if (strcmp(((char*)ExpEnv.analysis_struc.outfile), "STDERR")) { // print to file that is not stderr int stderrcopy = dup(2); // stderr backup if (strcmp(((char*)ExpEnv.analysis_struc.outfile), "STDOUT") == 0) { // print to stdout dup2(1, 2); // 2 is stderr; 1 is stdout -- dup2(1,2) redirects stderr output to stdout Pass.run(*M); // Run passes (results will be printed on stdout) dup2(stderrcopy, 2); // Recovers stderr } else { int Outputfile = open(((char*)ExpEnv.analysis_struc.outfile), O_CREAT | O_TRUNC | O_WRONLY, 0777); // Openning Output file, whose name is on 'ExpEnv.analysis_struc.outfile' if (Outputfile < 0) { fprintf(stderr, "Error:: I can not write analysis passes's output on %s...\n", ((char*)ExpEnv.analysis_struc.outfile)); fprintf(stderr, " %s...\n", strerror(errno)); errno = 0; exit(1); } dup2(Outputfile, 2); // 2 is stderr; Outputfile is any other file -- dup2(Outputfile,2) redirects stderr output to Outputfile Pass.run(*M); // Run passes (results will be printed on Outputfile) close(Outputfile); dup2(stderrcopy, 2); // Recovers stderr } close(stderrcopy); } else // print to stderr Pass.run(*M); // Run passes (results will be printed on stderr) } void JIT_Compiler::optimize_module(llvm::Module* &M) { if (ExpEnv.transform_struc.optlevel > -1) { /* Do I need to apply transform level? */ /* Yes, I do, so... */ /* Initializes PassManager for Function */ std::shared_ptr FPM; FPM.reset(new legacy::FunctionPassManager(M)); FPM->add(new DataLayoutPass()); PassManagerBuilder Builder; // aid to 'FPM' and 'MPM' /* Initializes PassManager for Function */ PassManager MPM; TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple())); MPM.add(TLI); MPM.add(new DataLayoutPass()); /* Populates 'Builder' */ Builder.OptLevel = ExpEnv.transform_struc.optlevel; Builder.DisableUnitAtATime = !ExpEnv.transform_struc.unit_at_time_enabled; //NOT IN LLVM 3.5 //Builder.DisableSimplifyLibCalls = !ExpEnv.transform_struc.simplify_libcalls_enabled; /* inline and unrool only be enabled if 'ExpEnv.transform_struc.optlevel' > 0 */ if (ExpEnv.transform_struc.optlevel) Builder.Inliner = createFunctionInliningPass(ExpEnv.transform_struc.opt_args.inline_threshold); Builder.DisableUnrollLoops = (ExpEnv.transform_struc.optlevel == 0); /***/ /***/ /* Populates 'FPM' from 'Builder' */ Builder.populateFunctionPassManager(*FPM); /* Populates 'MPM' from 'Builder' */ Builder.populateModulePassManager(MPM); /* * Enabling link-time optimizations -- default is no * * Use 'link_time_opt/1', 'link_time_opt/3', 'enable_link_time_opt/0', or 'enable_link_time_opt/2' to change * */ if (ExpEnv.transform_struc.link_time_opt.enabled) Builder.populateLTOPassManager(MPM /*, (bool)ExpEnv.transform_struc.link_time_opt.internalize, (bool)ExpEnv.transform_struc.link_time_opt.runinliner */); /***/ //set_regalloc_pass(MPM); /* Pass over all functions within Module and run passes */ FPM->doInitialization(); for (Module::iterator F = M->begin(), E = M->end(); F != E; ++F) FPM->run(*F); FPM->doFinalization(); /***/ MPM.run(*M); // Run passes on module } else { /* No, I need to apply transform passes accordingly transform predicates but transform_level/1 */ std::vector GVvector; // 'createGVExtractionPass' argument PassManager Pass; // 'Pass' stores transform passes to be applied TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple())); Pass.add(TLI); // First, I add on 'Pass' the Target Info of Module Pass.add(new DataLayoutPass()); // Second, I must add Target Data on 'Pass' for (int i = 0; i < ExpEnv.transform_struc.n; i++) { /* * 'ExpEnv.transform_struc.act_tr' contains sorted transform passes * * 'ExpEnv.transform_struc.act_tr' is filled by transform predicates * * What must I do? * * 1. Pass over 'ExpEnv.transform_struc.act_tr' (by previous 'for') * * 2. For each unity within 'ExpEnv.analysis_struc.act_an', add transform pass on 'Pass' * */ switch (ExpEnv.transform_struc.act_tr[i]) { case t_createAggressiveDCEPass: Pass.add(createAggressiveDCEPass()); break; case t_createArgumentPromotionPass: Pass.add(createArgumentPromotionPass((Int)ExpEnv.transform_struc.opt_args.arg_promotion_max_elements)); break; case t_createBBVectorizePass: Pass.add(createBBVectorizePass()); break; case t_createBlockExtractorPass: Pass.add(createBlockExtractorPass()); break; //NOT IN LLVM 3.5 //case t_createBlockPlacementPass: // Pass.add(createBlockPlacementPass()); // break; case t_createBreakCriticalEdgesPass: Pass.add(createBreakCriticalEdgesPass()); break; case t_createCFGSimplificationPass: Pass.add(createCFGSimplificationPass()); break; case t_createCodeGenPreparePass: Pass.add(createCodeGenPreparePass()); break; case t_createConstantMergePass: Pass.add(createConstantMergePass()); break; case t_createConstantPropagationPass: Pass.add(createConstantPropagationPass()); break; case t_createCorrelatedValuePropagationPass: Pass.add(createCorrelatedValuePropagationPass()); break; case t_createDeadArgEliminationPass: Pass.add(createDeadArgEliminationPass()); break; case t_createDeadArgHackingPass: Pass.add(createDeadArgHackingPass()); break; case t_createDeadCodeEliminationPass: Pass.add(createDeadCodeEliminationPass()); break; case t_createDeadInstEliminationPass: Pass.add(createDeadInstEliminationPass()); break; case t_createDeadStoreEliminationPass: Pass.add(createDeadStoreEliminationPass()); break; case t_createDemoteRegisterToMemoryPass: Pass.add(createDemoteRegisterToMemoryPass()); break; case t_createEarlyCSEPass: Pass.add(createEarlyCSEPass()); break; case t_createFunctionAttrsPass: Pass.add(createFunctionAttrsPass()); break; case t_createFunctionInliningPass: Pass.add(createFunctionInliningPass(ExpEnv.transform_struc.opt_args.inline_threshold)); break; case t_createGlobalDCEPass: Pass.add(createGlobalDCEPass()); break; case t_createGlobalOptimizerPass: Pass.add(createGlobalOptimizerPass()); break; case t_createGVExtractionPass: Pass.add(createGVExtractionPass(GVvector)); break; case t_createGVNPass: Pass.add(createGVNPass()); break; case t_createIndVarSimplifyPass: Pass.add(createIndVarSimplifyPass()); break; case t_createInstructionCombiningPass: Pass.add(createInstructionCombiningPass()); break; case t_createInstructionNamerPass: Pass.add(createInstructionNamerPass()); break; case t_createInstructionSimplifierPass: Pass.add(createInstructionSimplifierPass()); break; case t_createInternalizePass: Pass.add(createInternalizePass()); break; case t_createIPConstantPropagationPass: Pass.add(createIPConstantPropagationPass()); break; case t_createIPSCCPPass: Pass.add(createIPSCCPPass()); break; case t_createJumpThreadingPass: Pass.add(createJumpThreadingPass()); break; case t_createLCSSAPass: Pass.add(createLCSSAPass()); break; case t_createLICMPass: Pass.add(createLICMPass()); break; case t_createLoopDeletionPass: Pass.add(createLoopDeletionPass()); break; case t_createLoopExtractorPass: Pass.add(createLoopExtractorPass()); break; case t_createLoopIdiomPass: Pass.add(createLoopIdiomPass()); break; case t_createLoopInstSimplifyPass: Pass.add(createLoopInstSimplifyPass()); break; case t_createLoopRotatePass: Pass.add(createLoopRotatePass()); break; case t_createLoopSimplifyPass: Pass.add(createLoopSimplifyPass()); break; case t_createLoopStrengthReducePass: Pass.add(createLoopStrengthReducePass()); break; case t_createLoopUnrollPass: Pass.add(createLoopUnrollPass((Int)ExpEnv.transform_struc.opt_args.loop_unroll_threshold)); break; case t_createLoopUnswitchPass: Pass.add(createLoopUnswitchPass((bool)ExpEnv.transform_struc.opt_args.loop_unswitch_optimize_for_size)); break; case t_createLowerAtomicPass: Pass.add(createLowerAtomicPass()); break; case t_createLowerExpectIntrinsicPass: Pass.add(createLowerExpectIntrinsicPass()); break; case t_createLowerInvokePass: Pass.add(createLowerInvokePass()); break; case t_createLowerSwitchPass: Pass.add(createLowerSwitchPass()); break; case t_createMemCpyOptPass: Pass.add(createMemCpyOptPass()); break; case t_createMergeFunctionsPass: Pass.add(createMergeFunctionsPass()); break; case t_createObjCARCAPElimPass: Pass.add(createObjCARCAPElimPass()); break; case t_createObjCARCContractPass: Pass.add(createObjCARCContractPass()); break; case t_createObjCARCExpandPass: Pass.add(createObjCARCExpandPass()); break; case t_createObjCARCOptPass: Pass.add(createObjCARCOptPass()); break; case t_createPartialInliningPass: Pass.add(createPartialInliningPass()); break; case t_createPromoteMemoryToRegisterPass: Pass.add(createPromoteMemoryToRegisterPass()); break; case t_createPruneEHPass: Pass.add(createPruneEHPass()); break; case t_createReassociatePass: Pass.add(createReassociatePass()); break; case t_createScalarReplAggregatesPass: Pass.add(createScalarReplAggregatesPass((Int)ExpEnv.transform_struc.opt_args.scalar_replace_aggregates_threshold)); break; case t_createSCCPPass: Pass.add(createSCCPPass()); break; //NOT IN LLVM 3.5 //case t_createSimplifyLibCallsPass: // Pass.add(createSimplifyLibCallsPass()); // break; case t_createSingleLoopExtractorPass: Pass.add(createSingleLoopExtractorPass()); break; case t_createSinkingPass: Pass.add(createSinkingPass()); break; case t_createStripDeadDebugInfoPass: Pass.add(createStripDeadDebugInfoPass()); break; case t_createStripDeadPrototypesPass: Pass.add(createStripDeadPrototypesPass()); break; case t_createStripDebugDeclarePass: Pass.add(createStripDebugDeclarePass()); break; case t_createStripNonDebugSymbolsPass: Pass.add(createStripNonDebugSymbolsPass()); break; case t_createStripSymbolsPass: Pass.add(createStripSymbolsPass((bool)ExpEnv.transform_struc.opt_args.strip_symbols_pass_type)); break; case t_createTailCallEliminationPass: Pass.add(createTailCallEliminationPass()); break; default:; } } //set_regalloc_pass(Pass); Pass.run(*M); // Run passes } } void JIT_Compiler::set_regalloc_pass(PassManager &PM) { // 'ExpEnv.codegen_struc.struc_enginebuilder.regallocator' contains the active register allocator to be used switch(ExpEnv.codegen_struc.struc_enginebuilder.regallocator) { case REG_ALLOC_BASIC: PM.add(createBasicRegisterAllocator()); break; case REG_ALLOC_FAST: PM.add(createFastRegisterAllocator()); break; case REG_ALLOC_GREEDY: PM.add(createGreedyRegisterAllocator()); break; case REG_ALLOC_PBQP: PM.add(createDefaultPBQPRegisterAllocator()); break; } } void* JIT_Compiler::compile_all(LLVMContext* &Context, yamop* p) { /* Init llvm code generation, analysis and transform passes */ InitializeNativeTarget(); PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); initializeScalarOpts(Registry); initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); initializeIPA(Registry); initializeTransformUtils(Registry); initializeInstCombine(Registry); initializeInstrumentation(Registry); initializeTarget(Registry); sys::Process::PreventCoreFiles(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wwrite-strings" /* CLANG arguments */ char *clang_args[] = { "clang", "-fomit-frame-pointer", "-O0", #if CUT_C "-DCUT_C=1", #endif #if COROUTINING "-DCOROUTINING=1", #endif #if RATIONAL_TREES "-DRATIONAL_TREES=1", #endif #if DEBUG "-DDEBUG=1", #endif #if DEPTH_LIMIT "-DDEPTH_LIMIT=1", #endif #if YAP_DBG_PREDS "-DYAP_DBG_PREDS=1", #endif #if YAP_STAT_PREDS "-DYAP_STAT_PREDS=1", #endif #if TABLING "-DTABLING=1", #endif #if _YAP_NOT_INSTALLED_ "-D_YAP_NOT_INSTALLED_=1", #endif #ifdef HAVE_CONFIG_H "-DHAVE_CONFIG_H", #endif "-DYAP_JIT", "-D_NATIVE=1", "-I.", "-I./H", "-I./include", "-I./os", "-I./OPTYap", "-I./BEAM", "-I./MYDDAS", "-I./HPP", "-xc", "-c", "-", "-o", "-", "-emit-llvm", NULL }; #pragma GCC diagnostic pop std::string errStr; error_code e; /* Pipe to communicate 'echo' with 'clang' */ int pipe1[2]; int pid_echo, pid_clang ; /* 'clang' out file */ char* outputfilename = (char*)malloc(33*sizeof(char)); sprintf(outputfilename, "%lx.bc", (CELL)p); int Output = open(outputfilename, O_CREAT | O_RDWR, 0644); /* Creating pipes */ if (pipe(pipe1)<0) { perror(" ERROR!!\n ERROR") ; exit(1); } /* Calls echo. */ pid_echo = fork() ; if (pid_echo < 0) { perror(" ERROR!!\n ERROR") ; exit(1); } if (!pid_echo) { /* Setting echo's output to 1st pipe */ dup2(pipe1[1], 1); /* Closing pipes */ close(pipe1[0]); close(pipe1[1]); execlp("echo", "echo", p->y_u.J.jh->tcc.cmd, NULL); } else { /* Calls clang. */ pid_clang = fork() ; if (pid_clang < 0) { perror(" ERROR!!\n ERROR") ; exit(1); } if (!pid_clang) { /* Setting clang's input from 1st pipe */ dup2(pipe1[0], 0) ; /* Setting clang's output to Output */ dup2(Output, 1) ; /* Closing pipes */ close(pipe1[0]); close(pipe1[1]); execvp(*clang_args, clang_args); } } /* Closing pipes */ close(pipe1[0]); close(pipe1[1]); /* waiting for completion of processes */ int i; int *status = NULL; // 2 means two processes: 'echo' and 'clang' for (i = 0; i < 2; i++) wait(status); /***/ /* * At this point, the compiled code (O0) is on 'Output' * * I need to read it to main memory * * for this, I'll use 'MemoryBuffer::getOpenFile' * */ lseek(Output, 0, SEEK_SET); ErrorOr> em = MemoryBuffer::getOpenFile(Output, outputfilename, -1); e = em.getError(); if (e) { errs() << "ERROR::Unable to MemoryBuffer from " << outputfilename << " -- " << e.message() << "\n"; exit(1); } /* * At this point, the compiled code (O0) is on main memory * * I need to read it to Module * * for this, I'll use 'parseBitcodeFile' * */ ErrorOr ModuleOrErr = parseBitcodeFile(em.get()->getMemBufferRef(), *Context); std::unique_ptr M; if (std::error_code ec = ModuleOrErr.getError()) errs() << ec.message(); /* at last, get M */ M.reset(ModuleOrErr.get()); /* * verify module correctness * * predicates: * * enable_module_correctness/1 * * verify_module_before/0 * * verify_module_both/0 * */ if (ExpEnv.analysis_struc.pointtoverifymodule == BEFORE || ExpEnv.analysis_struc.pointtoverifymodule == BOTH) { if (verifyModule(*M)) { errs() << "ERROR:: Module not built correctly!\n"; exit(1); } } /***/ #if YAP_DBG_PREDS /* for debug... print module before optimizing it */ if (ExpEnv.debug_struc.pprint_llva.print_llva_before) errs() << "Module before optimization::\n" << *Mod; #endif llvm::Module *Mod = M.get(); /* Analyze module -- analysis predicates */ analyze_module(Mod); /* Optimize module -- transform predicates */ optimize_module(Mod); /* Computing size of optimized module */ { std::error_code ErrorInfo; /* Open file 'tmp.bc' which will be filled by optimized Module */ std::unique_ptr Out; Out.reset(new tool_output_file("tmp.bc", ErrorInfo, llvm::sys::fs::F_None)); if (ErrorInfo) { errs() << ErrorInfo.message() << '\n'; exit(1); } /* 'createPrintModulePass(arg)' will print Module (now optimized) to on file represented by 'arg' */ PassManager Pass; Pass.add(createPrintModulePass(Out->os())); Pass.run(*M); /* 'Out->keep()' will keep printed module to file and will close file */ Out->keep(); /* Open file 'tmp.bc' */ int Outtmp = open("tmp.bc", O_CREAT | O_RDWR, 0644); #if YAP_STAT_PREDS /* for statistics... compute file size and store value on 'NativeArea->area.native_size_bytes' */ NativeArea->area.native_size_bytes[p->y_u.jhc.jh->caa.naddress][NativeArea->area.nrecomp[p->y_u.jhc.jh->caa.naddress]-1] = lseek(Outtmp, 0, SEEK_END); #endif close(Outtmp); remove("tmp.bc"); } /***/\ #if YAP_DBG_PREDS /* for debug... print module after optimizing it */ if (ExpEnv.debug_struc.pprint_llva.print_llva_after) errs() << "Module after optimization::\n" << *Mod; #endif /* * verify module correctness * * predicates: * * enable_module_correctness/0 * * enable_module_correctness/1 * * verify_module_after/0 * * verify_module_both/0 * */ if (ExpEnv.analysis_struc.pointtoverifymodule == AFTER || ExpEnv.analysis_struc.pointtoverifymodule == BOTH) { if (verifyModule(*Mod)) { errs() << "ERROR:: Module not built correctly!\n"; exit(1); } } /***/ // materializeAllPermanently -- Make sure all GlobalValues in this Module are fully read error_code materialize_error = Mod->materializeAllPermanently(); if (materialize_error.value() != 0) { errs() <<"Error:: bitcode didn't read correctly. -- " << materialize_error.message() << "\n"; exit(1); } /* Creating EngineBuilder -- called 'builder' */ Function *EntryFn; llvm::CodeGenOpt::Level level; switch(ExpEnv.codegen_struc.struc_enginebuilder.engineoptlevel) { case 0: level = CodeGenOpt::None; break; case 1: level = CodeGenOpt::Less; break; case 2: level = CodeGenOpt::Default; break; case 3: level = CodeGenOpt::Aggressive; break; } // codegen predicate 'relocmodel/1' llvm::Reloc::Model relocmodel; switch(ExpEnv.codegen_struc.struc_enginebuilder.relocmodel) { case 0: relocmodel = Reloc::Default; break; case 1: relocmodel = Reloc::Static; break; case 2: relocmodel = Reloc::PIC_; break; case 3: relocmodel = Reloc::DynamicNoPIC; break; } // codegen predicate 'codemodel/1' llvm::CodeModel::Model codemodel; switch(ExpEnv.codegen_struc.struc_enginebuilder.codemodel) { case 0: codemodel = CodeModel::Default; break; case 1: codemodel = CodeModel::JITDefault; break; case 2: codemodel = CodeModel::Small; break; case 3: codemodel = CodeModel::Kernel; break; case 4: codemodel = CodeModel::Medium; break; case 5: codemodel = CodeModel::Large; break; } // MCJIT is default from 3.6 // codegen predicates 'enable_mcjit/0' or 'disable_mcjit/0' // builder.setUseMCJIT((bool)ExpEnv.codegen_struc.struc_enginebuilder.usemcjit); llvm::TargetOptions Options; { /* codegen predicates 'enable_framepointer_elimination/0' or 'disable_framepointer_elimination/0' */ Options.NoFramePointerElim = (bool)ExpEnv.codegen_struc.struc_targetopt.noframepointerelim; //NOT IN LLVM 3.5 //Options.NoFramePointerElimNonLeaf = (bool)ExpEnv.codegen_struc.struc_targetopt.noframepointerelim; /***/ // codegen predicates 'less_precise_fp_mad_option/0' or 'more_precise_fp_mad_option/0' Options.LessPreciseFPMADOption = (bool)ExpEnv.codegen_struc.struc_targetopt.lessprecisefpmadoption; // codegen predicates 'no_excess_fp_precision/0' or 'excess_fp_precision/0' //NOT IN LLVM 3.5 //Options.NoExcessFPPrecision = (bool)ExpEnv.codegen_struc.struc_targetopt.noexcessfpprecision; // codegen predicates 'unsafe_fp_math/0' or 'safe_fp_math/0' Options.UnsafeFPMath = (bool)ExpEnv.codegen_struc.struc_targetopt.unsafefpmath; // codegen predicates 'rounding_mode_dynamically_changed/0' or 'rounding_mode_not_changed/0' Options.HonorSignDependentRoundingFPMathOption = (bool)ExpEnv.codegen_struc.struc_targetopt.honorsigndependentroundingfpmathoption; // codegen predicates 'no_use_soft_float/0' or 'use_soft_float/0' Options.UseSoftFloat = (bool)ExpEnv.codegen_struc.struc_targetopt.usesoftfloat; // codegen predicates 'enable_jit_exception_handling/0' or 'disable_jit_exception_handling/0' //NOT IN LLVM 3.5 //Options.JITExceptionHandling = (bool)ExpEnv.codegen_struc.struc_targetopt.jitexceptionhandling; // codegen predicates 'enable_jit_emit_debug_info/0' or 'disable_jit_emit_debug_info/0' Options.JITEmitDebugInfo = (bool)ExpEnv.codegen_struc.struc_targetopt.jitemitdebuginfo; // codegen predicates 'enable_jit_emit_debug_info_to_disk/0' or 'disable_jit_emit_debug_info_to_disk/0' Options.JITEmitDebugInfoToDisk = (bool)ExpEnv.codegen_struc.struc_targetopt.jitemitdebuginfotodisk; // codegen predicates 'guaranteed_tail_call_opt/0' or 'no_guaranteed_tail_call_opt/0' Options.GuaranteedTailCallOpt = (bool)ExpEnv.codegen_struc.struc_targetopt.guaranteedtailcallopt; // codegen predicates 'enable_tail_calls/0' or 'disable_tail_calls/0' Options.DisableTailCalls = (bool)ExpEnv.codegen_struc.struc_targetopt.disabletailcalls; // codegen predicates 'enable_fast_isel/0' or 'disable_fast_isel/0' Options.EnableFastISel = (bool)ExpEnv.codegen_struc.struc_targetopt.fastisel; } // codegen predicates 'fp_abitype/1' or 'default_fp_abitype/0' switch(ExpEnv.codegen_struc.struc_targetopt.floatabitype) { case 0: Options.FloatABIType = FloatABI::Default; break; case 1: Options.FloatABIType = FloatABI::Soft; break; case 2: Options.FloatABIType = FloatABI::Hard; break; } // codegen predicate 'engine_opt_level/1' /* Creating ExecutionEngine from EngineBuilder (builder) */ ExecutionEngine *EE = EngineBuilder(std::move(M)) .setErrorStr(&errStr) .setOptLevel( level ) .setRelocationModel( relocmodel ) .setCodeModel( codemodel ) .setEngineKind(EngineKind::JIT) .setTargetOptions(Options) // check class in Kaleidoscope example. // .setMCJITMemoryManager(std::unique_ptr( // new HelpingMemoryManager(this))) .setMCJITMemoryManager(std::unique_ptr(new SectionMemoryManager())) .create(); if (!EE) { if (!errStr.empty()) errs() << "Error creating Execution Engine: " << errStr << "\n"; else errs() << "Unknown error creating Execution Engine!\n"; exit(1); } /***/ // 'clause' is our function -- getting it from Module EntryFn = Mod->getFunction("clause"); if (!EntryFn) { /* * Theoretically, every Module is correct, but * * for some reason, llvm can not compile some of them * */ close(Output); remove(outputfilename); free(p->y_u.J.jh->tcc.cmd); free(outputfilename); return NULL; } /* Here, we know that Module was be successfully compiled, so... */ // 1. execute all of the static constructors or destructors for program EE->runStaticConstructorsDestructors(false); // global++; what is this? close(Output); remove(outputfilename); free(p->y_u.J.jh->tcc.cmd); free(outputfilename); // 2. get native pointer from 'clause' (our function within Module) and return it return EE->getPointerToFunction(EntryFn); } void* JIT_Compiler::compile(yamop* p) { /* LLVMContext must be declared here, otherwise LLVM will crash on x86_64 machines */ LLVMContext *Context = new LLVMContext(); return compile_all(Context, p); }