main_func_type jit_engine::compile(const ast::Program &prog) { llvm::LLVMContext &c=llvm::getGlobalContext(); llvm::Module *m=new llvm::Module("brainfuck", c); brainfuck::codegen(*m, prog); //m->dump(); std::string ErrStr; ExecutionEngine *TheExecutionEngine = EngineBuilder(m).setErrorStr(&ErrStr).create(); if (!TheExecutionEngine) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } Function *f_main=m->getFunction("main"); // Optimize, target dependant if(optimization_level_>0) { FunctionPassManager OurFPM(m); // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); // Provide basic AliasAnalysis support for GVN. OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(createCFGSimplificationPass()); //OurFPM.add(createLoopSimplifyPass()); //OurFPM.add(createBlockPlacementPass()); //OurFPM.add(createConstantPropagationPass()); OurFPM.doInitialization(); OurFPM.run(*f_main); } //m->dump(); void *rp=TheExecutionEngine->getPointerToFunction(f_main); main_func_type fp=reinterpret_cast<main_func_type>(rp); return fp; }
void CouchRunner::runIR( CouchWorkingMemory *wm ){ /* Module *theM; theM = ParseBitcodeFile( MemoryBuffer::getFile("out.bc"), getGlobalContext(), &error ); */ // Loads intermediate representation source std::string error; SMDiagnostic Err; std::auto_ptr<Module> theM(ParseAssemblyFile( fSourceFile, Err, getGlobalContext() )); std::cout << "KBVM v1.0 (experimental)\nIntermediate Representation Interpreter\n"; std::cout << "Parsing " << fSourceFile << "\n"; // Verifies module try{ std::string VerifErr; if (verifyModule( *theM.get(), ReturnStatusAction, &VerifErr)) { errs() << fSourceFile << ": assembly parsed, but does not verify as correct!\n"; errs() << VerifErr; return; } } catch(...){ std::cerr << "Verification of module failed!\n"; return; } // Prepares to execute S_wm = wm; IRBuilder<> theBuilder( getGlobalContext() ); // Create the JIT. S_TheExecutionEngine = ExecutionEngine::create(theM.get()); //ExistingModuleProvider OurModuleProvider( M ); FunctionPassManager OurFPM( theM.get() ); // Set up the optimizer pipeline. // Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*S_TheExecutionEngine->getTargetData())); // Promote allocas to registers. OurFPM.add(createPromoteMemoryToRegisterPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(createCFGSimplificationPass()); // Set the global so the code gen can use this. S_TheFPM = &OurFPM; // Inital setup of the agenda unsigned int i; CouchRunner::S_Agenda->reset(); // Initial setup of the working memory S_TheFPM->run( *theM->getFunction("ag_forward") ); std::string sign, val; Function *FFwrd = S_TheExecutionEngine->FindFunctionNamed( "ag_forward" ); void *FFwrdPtr = S_TheExecutionEngine->getPointerToFunction(FFwrd); void (*FFwrdP)(const char*) = (void (*)( const char*))FFwrdPtr; DOMElement *elt; DOMNodeList *domSuggests = fDom->getElementsByTagName( XMLString::transcode("suggest") ); for( i = 0; i < domSuggests->getLength(); i++ ){ CouchRunner::S_Agenda->push( std::string(XMLString::transcode( ((DOMText *)(domSuggests->item(i)->getFirstChild()))->getData() )), S_wm ); } DOMNodeList *domVolunteers = fDom->getElementsByTagName( XMLString::transcode("volunteer") ); for( i = 0; i < domVolunteers->getLength(); i++ ){ elt = (DOMElement *)(domVolunteers->item(i)); sign = std::string( XMLString::transcode( ((DOMText *)(elt->getElementsByTagName(XMLString::transcode("var"))->item(0)->getFirstChild()))->getData() ) ); val = std::string( XMLString::transcode( ((DOMText *)(elt->getElementsByTagName(XMLString::transcode("const"))->item(0)->getFirstChild()))->getData() ) ); // TODO: update with type information if( std::string("true") == val ){ S_wm->set( sign.c_str(), (int)1 ); } else if( std::string("false") == val ){ S_wm->set( sign.c_str(), (int)0 ); } else if( isalpha( *(val.c_str()) ) ){ S_wm->set( sign.c_str(), val.c_str() ); } else{ double d = strtod( val.c_str(), NULL ); S_wm->set( sign.c_str(), d ); } // Update agenda as if forwarded from execution FFwrdP( sign.c_str() ); } std::cout << "Session Started\n" << *S_wm << *CouchRunner::S_Agenda; { // Creates the `entry' function that sets up the Agenda, which // also serves as continuation for the postponed calls std::vector<Value *> args; Function *Main; while( !CouchRunner::S_Agenda->empty() ){ // Erase previous entry function if present if( NULL != (Main = theM->getFunction("entry")) ){ Main->eraseFromParent(); } // Creates code block Main = cast<Function>( theM->getOrInsertFunction( "entry", Type::getInt32Ty(getGlobalContext()), (Type *)0) ); BasicBlock *EB = BasicBlock::Create(getGlobalContext(), "EntryBlock", Main); theBuilder.SetInsertPoint(EB); // Loops through the current agenda Value *res = NULL, *call; std::string hypo; // Copies agenda to current Agenda while( !CouchRunner::S_Agenda->empty() ){ hypo = CouchRunner::S_Agenda->pop(); if( WorkingMemory::WM_UNKNOWN == S_wm->knownp( hypo.c_str() ) ){ call = theBuilder.CreateCall(theM->getFunction( hypo ), args.begin(), args.end(), "suggest"); res = theBuilder.CreateIntCast( call, Type::getInt32Ty(getGlobalContext()), false, "cast_tmp" ); } } theBuilder.CreateRet( res == NULL ? ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 2) : res ); // Check it S_TheFPM->run( *Main ); // Run it Function *F = S_TheExecutionEngine->FindFunctionNamed( "entry" ); void *FPtr = S_TheExecutionEngine->getPointerToFunction(F); typedef int (*PFN)(); PFN FP = reinterpret_cast<PFN>( FPtr ); // int (*FP)() = (int (*)())FPtr; printf( "Result = %d\n", FP() ); std::cout << *S_wm << std::endl; std::cout << *CouchRunner::S_Agenda << std::endl; } S_wm = NULL; } }
int main() { llvm::InitializeNativeTarget(); // Make the module, which holds all the code. llvm::Module *TheModule = new llvm::Module("my cool jit", llvm::getGlobalContext()); // Create the JIT. This takes ownership of the module. std::string ErrStr; llvm::ExecutionEngine *TheExecutionEngine = llvm::EngineBuilder(TheModule).setErrorStr(&ErrStr).create(); if (!TheExecutionEngine) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } llvm::FunctionPassManager OurFPM(TheModule); // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new llvm::TargetData(*TheExecutionEngine->getTargetData())); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(llvm::createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(llvm::createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(llvm::createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(llvm::createCFGSimplificationPass()); OurFPM.doInitialization(); // Set the global so the code gen can use this. llvm::FunctionPassManager *TheFPM = &OurFPM; // Single argument std::vector<const llvm::Type*> unaryArg(1,llvm::Type::getDoubleTy(llvm::getGlobalContext())); // Two arguments std::vector<const llvm::Type*> binaryArg(2,llvm::Type::getDoubleTy(llvm::getGlobalContext())); // Two arguments in and two references std::vector<const llvm::Type*> genArg(4); genArg[0] = genArg[1] = llvm::Type::getDoubleTy(llvm::getGlobalContext()); genArg[2] = genArg[3] = llvm::Type::getDoublePtrTy(llvm::getGlobalContext()); // Unary operation llvm::FunctionType *unaryFun = llvm::FunctionType::get(llvm::Type::getDoubleTy(llvm::getGlobalContext()),unaryArg, false); // Binary operation llvm::FunctionType *binaryFun = llvm::FunctionType::get(llvm::Type::getDoubleTy(llvm::getGlobalContext()),binaryArg, false); // More generic operation, return by reference llvm::FunctionType *genFun = llvm::FunctionType::get(llvm::Type::getVoidTy(llvm::getGlobalContext()),genArg, false); // Declare sin llvm::Function *sin_ = llvm::Function::Create(unaryFun, llvm::Function::ExternalLinkage, "sin", TheModule); // Declare my function llvm::Function *myfun = llvm::Function::Create(genFun, llvm::Function::ExternalLinkage, "myfcn", TheModule); // Create a new basic block to start insertion into. llvm::BasicBlock *BB = llvm::BasicBlock::Create(llvm::getGlobalContext(), "entry", myfun); Builder.SetInsertPoint(BB); // Set names for all arguments. llvm::Function::arg_iterator AI = myfun->arg_begin(); AI->setName("x1"); llvm::Value *x1 = AI; AI++; AI->setName("x2"); llvm::Value *x2 = AI; AI++; AI->setName("r1"); llvm::Value *r1 = AI; AI++; AI->setName("r2"); llvm::Value *r2 = AI; llvm::Value *five = llvm::ConstantFP::get(llvm::getGlobalContext(), llvm::APFloat(5.0)); llvm::Value *x1_plus_5 = Builder.CreateFAdd(x1, five, "x1_plus_5"); // Call the sine function std::vector<llvm::Value*> sinarg(1,x2); llvm::Value* sin_x2 = Builder.CreateCall(sin_, sinarg.begin(), sinarg.end(), "callsin"); // Set values llvm::StoreInst *what_is_this1 = Builder.CreateStore(sin_x2,r1); llvm::StoreInst *what_is_this2 = Builder.CreateStore(x1_plus_5,r2); // Finish off the function. Builder.CreateRetVoid(); // Validate the generated code, checking for consistency. verifyFunction(*myfun); // Optimize the function. TheFPM->run(*myfun); // Print out all of the generated code. TheModule->dump(); // JIT the function double x1_val = 10; double x2_val = 20; double r1_val = -1; double r2_val = -1; typedef void (*GenType)(double,double,double*,double*); GenType FP = GenType(intptr_t(TheExecutionEngine->getPointerToFunction(myfun))); FP(x1_val,x2_val,&r1_val,&r2_val); printf("r1 = %g\n", r1_val); printf("r2 = %g\n", r2_val); return 0; }
static int Execute(llvm::Module *Mod) { llvm::InitializeNativeTarget(); std::string Error; llvm::OwningPtr<llvm::ExecutionEngine> EE(llvm::ExecutionEngine::createJIT(Mod, &Error, 0, llvm::CodeGenOpt::Aggressive)); if (!EE) { llvm::errs() << "unable to make execution engine: " << Error << "\n"; return 255; } //should get a better way to resolve the name? (c++filt like) llvm::Function *EntryFn = Mod->getFunction("_Z4testii"); if (!EntryFn) { llvm::errs() << "'_Z4testii' function not found in module.\n"; return 255; } // Validate the generated code, checking for consistency. llvm::verifyFunction(*EntryFn); //now further optimize here i guess llvm::FunctionPassManager OurFPM(Mod); // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new llvm::DataLayout(*EE->getDataLayout())); // Provide basic AliasAnalysis support for GVN. OurFPM.add(llvm::createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(llvm::createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(llvm::createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(llvm::createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(llvm::createCFGSimplificationPass()); OurFPM.doInitialization(); // Optimize the function. OurFPM.run(*EntryFn); std::vector<std::string> Args; Args.push_back(Mod->getModuleIdentifier()); for(unsigned int i = 0; i < Args.size(); ++i) { printf("mod argumend[%i]: %s", i, Args[0].c_str()); } void *FPtr = EE->getPointerToFunction(EntryFn); if(!FPtr) { llvm::errs() << "unable to get pointer to function.\n"; return 1; } // A b; // b.b = 666; // // void (*FP)(A) = (void (*)(A))(intptr_t)FPtr; // // FP(b); // void (*FP)() = (void (*)())(intptr_t)FPtr; // // FP(); int (*FP)(int, int) = (int (*)(int, int))(intptr_t)FPtr; int c = FP(4, 30); printf("\n\nresult is %i\n", c); //cleanup EntryFn->eraseFromParent(); EE->removeModule(Mod); delete Mod; return 0; }