//--------------------------------------------------------------------------------------------------------------- int createCompiledFunction2(int fntype, int fn, int code1, int code2) { int size2; unsigned char *block; unsigned char *outp; int myfunc; int sizes1=((int *)code1)[0]; int sizes2=((int *)code2)[0]; myfunc = getFunctionAddress(fntype, fn, &size2); block=(unsigned char *)newTmpBlock(2+size2+sizes1+sizes2+4); ((int*)block)[0]=2+size2+sizes1+sizes2; outp=block+4; memcpy(outp,(char*)code1+4,sizes1); outp+=sizes1; *outp++ = X86_PUSH_EAX; memcpy(outp,(char*)code2+4,sizes2); outp+=sizes2; *outp++ = X86_POP_EBX; memcpy(block+4+2+sizes1+sizes2,(void*)myfunc,size2); g_evallib_computTableTop++; return ((int)(block)); }
//--------------------------------------------------------------------------------------------------------------- int createCompiledFunction1(int fntype, int fn, int code) { int size,size2; char *block; int myfunc; void *func1; size =((int *)code)[0]; func1 = (void *)(code+4); myfunc = getFunctionAddress(fntype, fn, &size2); block=(char *)newTmpBlock(4+size+size2); ((int*)block)[0]=size+size2; memcpy(block+4, func1, size); memcpy(block+size+4,(void*)myfunc,size2); g_evallib_computTableTop++; return ((int)(block)); }
//--------------------------------------------------------------------------------------------------------------- int createCompiledFunction3(int fntype, int fn, int code1, int code2, int code3) { int sizes1=((int *)code1)[0]; int sizes2=((int *)code2)[0]; int sizes3=((int *)code3)[0]; if (fntype == MATH_FN && fn == 0) // special case: IF { void *func3; int size; int *ptr; char *block; unsigned char *newblock2,*newblock3; newblock2=newBlock(sizes2+1); memcpy(newblock2,(char*)code2+4,sizes2); newblock2[sizes2]=X86_RET; newblock3=newBlock(sizes3+1); memcpy(newblock3,(char*)code3+4,sizes3); newblock3[sizes3]=X86_RET; l_stats[2]+=sizes2+sizes3+2; func3 = realAddress(_asm_if,_asm_if_end,&size); block=(char *)newTmpBlock(4+sizes1+size); ((int*)block)[0]=sizes1+size; memcpy(block+4,(char*)code1+4,sizes1); ptr=(int *)(block+4+sizes1); memcpy(ptr,func3,size); ptr=findFBlock((char*)ptr); *ptr++=(int)newblock2; ptr=findFBlock((char*)ptr); *ptr=(int)newblock3; return (int)block; } else { int size2; unsigned char *block; unsigned char *outp; int myfunc; myfunc = getFunctionAddress(fntype, fn, &size2); block=(unsigned char *)newTmpBlock(4+size2+sizes1+sizes2+sizes3+4); ((int*)block)[0]=4+size2+sizes1+sizes2+sizes3; outp=block+4; memcpy(outp,(char*)code1+4,sizes1); outp+=sizes1; *outp++ = X86_PUSH_EAX; memcpy(outp,(char*)code2+4,sizes2); outp+=sizes2; *outp++ = X86_PUSH_EAX; memcpy(outp,(char*)code3+4,sizes3); outp+=sizes3; *outp++ = X86_POP_EBX; *outp++ = X86_POP_ECX; memcpy(block+4+4+sizes1+sizes2+sizes3,(void*)myfunc,size2); g_evallib_computTableTop++; return ((int)(block)); } }
int test1() { // Get global context - not sure what the impact is of sharing // the global context llvm::LLVMContext &context = llvm::getGlobalContext(); // Module is the translation unit std::unique_ptr<llvm::Module> theModule = std::unique_ptr<llvm::Module>(new llvm::Module("ravi", context)); llvm::Module *module = theModule.get(); llvm::IRBuilder<> builder(context); #if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MINOR < 7) // On Windows we get error saying incompatible object format // Reading posts on mailining lists I found that the issue is that COEFF // format is not supported and therefore we need to set -elf as the object // format auto triple = llvm::sys::getProcessTriple(); // module->setTargetTriple("x86_64-pc-win32-elf"); module->setTargetTriple(triple + "-elf"); #endif // create a GCObject structure as defined in lobject.h llvm::StructType *structType = llvm::StructType::create(context, "RaviGCObject"); llvm::PointerType *pstructType = llvm::PointerType::get(structType, 0); // pointer to RaviGCObject std::vector<llvm::Type *> elements; elements.push_back(pstructType); elements.push_back(llvm::Type::getInt8Ty(context)); elements.push_back(llvm::Type::getInt8Ty(context)); structType->setBody(elements); structType->dump(); // Create printf declaration std::vector<llvm::Type *> args; args.push_back(llvm::Type::getInt8PtrTy(context)); // accepts a char*, is vararg, and returns int llvm::FunctionType *printfType = llvm::FunctionType::get(builder.getInt32Ty(), args, true); llvm::Constant *printfFunc = module->getOrInsertFunction("printf", printfType); // Create the testfunc() args.clear(); args.push_back(pstructType); llvm::FunctionType *funcType = llvm::FunctionType::get(builder.getInt32Ty(), args, false); llvm::Function *mainFunc = llvm::Function::Create( funcType, llvm::Function::ExternalLinkage, "testfunc", module); llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entrypoint", mainFunc); builder.SetInsertPoint(entry); // printf format string llvm::Value *formatStr = builder.CreateGlobalStringPtr("value = %d\n"); // Get the first argument which is RaviGCObject * auto argiter = mainFunc->arg_begin(); llvm::Value *arg1 = argiter++; arg1->setName("obj"); // Now we need a GEP for the second field in RaviGCObject std::vector<llvm::Value *> values; llvm::APInt zero(32, 0); llvm::APInt one(32, 1); // This is the array offset into RaviGCObject* values.push_back( llvm::Constant::getIntegerValue(llvm::Type::getInt32Ty(context), zero)); // This is the field offset values.push_back( llvm::Constant::getIntegerValue(llvm::Type::getInt32Ty(context), one)); // Create the GEP value llvm::Value *arg1_a = builder.CreateGEP(arg1, values, "ptr"); // Now retrieve the data from the pointer address llvm::Value *tmp1 = builder.CreateLoad(arg1_a, "a"); // As the retrieved value is a byte - convert to int i llvm::Value *tmp2 = builder.CreateZExt(tmp1, llvm::Type::getInt32Ty(context), "i"); // Call the printf function values.clear(); values.push_back(formatStr); values.push_back(tmp2); builder.CreateCall(printfFunc, values); // return i builder.CreateRet(tmp2); module->dump(); // Lets create the MCJIT engine std::string errStr; #if LLVM_VERSION_MINOR > 5 std::unique_ptr<llvm::Module> module_(module); auto engine = llvm::EngineBuilder(std::move(module_)) .setErrorStr(&errStr) .setEngineKind(llvm::EngineKind::JIT) .create(); #else auto engine = llvm::EngineBuilder(module) .setErrorStr(&errStr) .setEngineKind(llvm::EngineKind::JIT) .setUseMCJIT(true) .create(); #endif if (!engine) { std::cerr << "Failed to construct MCJIT ExecutionEngine: " << errStr << "\n"; return 1; } // Now lets compile our function into machine code std::string funcname = "testfunc"; myfunc_t funcptr = (myfunc_t)engine->getFunctionAddress(funcname); if (funcptr == nullptr) { std::cerr << "Failed to obtain compiled function\n"; return 1; } // Run the function and test results. RaviGCObject obj = {NULL, 42, 65}; int ans = funcptr(&obj); printf("The answer is %d\n", ans); return ans == 42 ? 0 : 1; }