Function * futamurize( const Function * orig_func, DenseMap<const Value*, Value*> &argmap, std::set<const unsigned char *> &constant_addresses_set ) { LLVMContext &context = getGlobalContext(); // Make a copy of the function, removing constant arguments Function * specialized_func = CloneFunction( orig_func, argmap ); specialized_func->setName( orig_func->getNameStr() + "_1" ); // add it to our module LLVM_Module->getFunctionList().push_back( specialized_func ); printf("\nspecialized_func = %p <%s>\n", specialized_func, specialized_func->getName().data()); //~ specialized_func->dump(); // Optimize it FunctionPassManager PM( LLVM_Module ); createStandardFunctionPasses( &PM, 3 ); PM.add(createScalarReplAggregatesPass()); // Break up aggregate allocas PM.add(createInstructionCombiningPass()); // Cleanup for scalarrepl. PM.add(createJumpThreadingPass()); // Thread jumps. PM.add(createCFGSimplificationPass()); // Merge & remove BBs PM.add(createInstructionCombiningPass()); // Combine silly seq's PM.add(createTailCallEliminationPass()); // Eliminate tail calls PM.add(createCFGSimplificationPass()); // Merge & remove BBs PM.add(createReassociatePass()); // Reassociate expressions PM.add(createLoopRotatePass()); // Rotate Loop PM.add(createLICMPass()); // Hoist loop invariants PM.add(createLoopUnswitchPass( false )); PM.add(createInstructionCombiningPass()); PM.add(createIndVarSimplifyPass()); // Canonicalize indvars PM.add(createLoopDeletionPass()); // Delete dead loops PM.add(createLoopUnroll2Pass()); // Unroll small loops PM.add(createInstructionCombiningPass()); // Clean up after the unroller PM.add(createGVNPass()); // Remove redundancies PM.add(createMemCpyOptPass()); // Remove memcpy / form memset PM.add(createSCCPPass()); // Constant prop with SCCP PM.add(createPromoteMemoryToRegisterPass()); PM.add(createConstantPropagationPass()); PM.add(createDeadStoreEliminationPass()); PM.add(createAggressiveDCEPass()); PM.add(new MemoryDependenceAnalysis()); //~ PM.add(createAAEvalPass()); const PassInfo * pinfo = Pass::lookupPassInfo( "print-alias-sets" ); if( !pinfo ) { printf( "print-alias-sets not found\n" ); exit(-1); } PM.add( pinfo->createPass() ); FunctionPassManager PM_Inline( LLVM_Module ); PM_Inline.add(createSingleFunctionInliningPass()); bool Changed = false; int iterations = 2; int inline_iterations = 6; do { Changed = false; // first do some optimizations PM.doInitialization(); PM.run( *specialized_func ); PM.doFinalization(); // Load from Constant Memory detection const TargetData *TD = LLVM_EE->getTargetData(); for (inst_iterator I = inst_begin(specialized_func), E = inst_end(specialized_func); I != E; ++I) { Instruction * inst = (Instruction *) &*I; // get all Load instructions LoadInst * load = dyn_cast<LoadInst>( inst ); if( !load ) continue; if( load->isVolatile() ) continue; if (load->use_empty()) continue; // Don't muck with dead instructions... // get the address loaded by load instruction Value *ptr_value = load->getPointerOperand(); // we're only interested in constant addresses ConstantExpr * ptr_constant_expr = dyn_cast<ConstantExpr>( ptr_value ); if( !ptr_constant_expr ) continue; ptr_constant_expr->dump(); // compute real address of constant pointer expression Constant * ptr_constant = ConstantFoldConstantExpression( ptr_constant_expr, TD ); if( !ptr_constant ) continue; ptr_constant->dump(); // convert to int constant ConstantInt *int_constant = dyn_cast<ConstantInt>( ConstantExpr::getPtrToInt( ptr_constant, Type::getInt64Ty( context ))); if( !int_constant ) continue; int_constant->dump(); // get data size int data_length = TD->getTypeAllocSize( load->getType() ); ptr_value->getType()->dump(); // get real address (at last !) const unsigned char * c_ptr = (const unsigned char *) int_constant->getLimitedValue(); printf( "%ld %d %d\n", c_ptr, constant_addresses_set.count( c_ptr ), data_length ); // check what's in this address int isconst = 1; for( int offset=0; offset<data_length; offset++ ) isconst &= constant_addresses_set.count( c_ptr + offset ); if( !isconst ) continue; printf( "It is constant.\n" ); // make a LLVM const with the data Constant *new_constant = NULL; switch( data_length ) { case 1: new_constant = ConstantInt::get( Type::getInt8Ty( context ), *(uint8_t*)c_ptr, false /* signed */ ); break; case 2: new_constant = ConstantInt::get( Type::getInt16Ty( context ), *(uint16_t*)c_ptr, false /* signed */ ); break; case 4: new_constant = ConstantInt::get( Type::getInt32Ty( context ), *(uint32_t*)c_ptr, false /* signed */ ); break; case 8: new_constant = ConstantInt::get( Type::getInt64Ty( context ), *(uint64_t*)c_ptr, false /* signed */ ); break; default: { StringRef const_data ( (const char *) c_ptr, data_length ); new_constant = ConstantArray::get( context, const_data, false /* dont add terminating null */ ); } } if( !new_constant ) continue; new_constant->dump(); //~ // get the type that is loaded const Type *Ty = load->getType(); // do we need a cast ? if( load->getType() != new_constant->getType() ) { new_constant = ConstantExpr::getBitCast( new_constant, Ty ); new_constant->dump(); } // zap the load and replace with constant address load->replaceAllUsesWith( new_constant ); printf( "\nREPLACED :...\n" ); load->dump(); new_constant->dump(); Changed = true; } if( Changed ) continue; // re-optimize and do another pass of constant load elimination // if we can't do anything else, do an inlining pass if( inline_iterations > 0 ) { inline_iterations --; PM_Inline.doInitialization(); Changed |= PM_Inline.run( *specialized_func ); PM_Inline.doFinalization(); //~ for( int i=0; i<3; i++ ) { PM.doInitialization(); Changed |= PM.run( *specialized_func ); PM.doFinalization(); } } if( iterations>0 && !Changed ) iterations--; } while( Changed || iterations>0 ); return specialized_func; }
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; } }
FakeAudio::FakeAudio() : onendedCallback(getGlobalContext()) { readyState = 0; volume = 1.0f; }
static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_name, jl_codectx_t *ctx) { // in pseudo-code, this function emits the following: // global uv_lib_t **libptrgv // global void **llvmgv // if (*llvmgv == NULL) { // *llvmgv = jl_load_and_lookup(f_lib, f_name, libptrgv); // } // return (*llvmgv) Constant *initnul = ConstantPointerNull::get((PointerType*)T_pint8); uv_lib_t *libsym = NULL; bool runtime_lib = false; GlobalVariable *libptrgv; #ifdef _OS_WINDOWS_ if ((intptr_t)f_lib == 1) { libptrgv = prepare_global(jlexe_var); libsym = jl_exe_handle; } else if ((intptr_t)f_lib == 2) { libptrgv = prepare_global(jldll_var); libsym = jl_dl_handle; } else #endif if (f_lib == NULL) { libptrgv = prepare_global(jlRTLD_DEFAULT_var); libsym = jl_RTLD_DEFAULT_handle; } else { runtime_lib = true; libptrgv = libMapGV[f_lib]; if (libptrgv == NULL) { libptrgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, f_lib); libMapGV[f_lib] = libptrgv; libsym = get_library(f_lib); assert(libsym != NULL); #ifdef USE_MCJIT llvm_to_jl_value[libptrgv] = libsym; #else *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)) = libsym; #endif } } if (libsym == NULL) { #ifdef USE_MCJIT libsym = (uv_lib_t*)llvm_to_jl_value[libptrgv]; #else libsym = *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)); #endif } assert(libsym != NULL); GlobalVariable *llvmgv = symMapGV[f_name]; if (llvmgv == NULL) { // MCJIT forces this to have external linkage eventually, so we would clobber // the symbol of the actual function. std::string name = f_name; name = "ccall_" + name; llvmgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, name); symMapGV[f_name] = llvmgv; #ifdef USE_MCJIT llvm_to_jl_value[llvmgv] = jl_dlsym_e(libsym, f_name); #else *((void**)jl_ExecutionEngine->getPointerToGlobal(llvmgv)) = jl_dlsym_e(libsym, f_name); #endif } BasicBlock *dlsym_lookup = BasicBlock::Create(getGlobalContext(), "dlsym"), *ccall_bb = BasicBlock::Create(getGlobalContext(), "ccall"); builder.CreateCondBr(builder.CreateICmpNE(builder.CreateLoad(llvmgv), initnul), ccall_bb, dlsym_lookup); ctx->f->getBasicBlockList().push_back(dlsym_lookup); builder.SetInsertPoint(dlsym_lookup); Value *libname; if (runtime_lib) { libname = builder.CreateGlobalStringPtr(f_lib); } else { libname = literal_static_pointer_val(f_lib, T_pint8); } Value *llvmf = builder.CreateCall3(prepare_call(jldlsym_func), libname, builder.CreateGlobalStringPtr(f_name), libptrgv); builder.CreateStore(llvmf, llvmgv); builder.CreateBr(ccall_bb); ctx->f->getBasicBlockList().push_back(ccall_bb); builder.SetInsertPoint(ccall_bb); llvmf = builder.CreateLoad(llvmgv); return builder.CreatePointerCast(llvmf,funcptype); }
// ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { JL_NARGSV(ccall, 3); jl_value_t *ptr=NULL, *rt=NULL, *at=NULL; Value *jl_ptr=NULL; JL_GC_PUSH(&ptr, &rt, &at); ptr = static_eval(args[1], ctx, true); if (ptr == NULL) { jl_value_t *ptr_ty = expr_type(args[1], ctx); Value *arg1 = emit_unboxed(args[1], ctx); if (!jl_is_cpointer_type(ptr_ty)) { emit_typecheck(arg1, (jl_value_t*)jl_voidpointer_type, "ccall: function argument not a pointer or valid constant", ctx); } jl_ptr = emit_unbox(T_size, T_psize, arg1); } rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); if (jl_is_tuple(rt)) { std::string msg = "in " + ctx->funcName + ": ccall: missing return type"; jl_error(msg.c_str()); } at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); void *fptr=NULL; char *f_name=NULL, *f_lib=NULL; if (ptr != NULL) { if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) { ptr = jl_tupleref(ptr,0); } if (jl_is_symbol(ptr)) f_name = ((jl_sym_t*)ptr)->name; else if (jl_is_byte_string(ptr)) f_name = jl_string_data(ptr); if (f_name != NULL) { // just symbol, default to JuliaDLHandle #ifdef __WIN32__ //TODO: store the f_lib name instead of fptr fptr = jl_dlsym_win32(f_name); #else // will look in process symbol table #endif } else if (jl_is_cpointer_type(jl_typeof(ptr))) { fptr = *(void**)jl_bits_data(ptr); } else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) { jl_value_t *t0 = jl_tupleref(ptr,0); jl_value_t *t1 = jl_tupleref(ptr,1); if (jl_is_symbol(t0)) f_name = ((jl_sym_t*)t0)->name; else if (jl_is_byte_string(t0)) f_name = jl_string_data(t0); else JL_TYPECHK(ccall, symbol, t0); if (jl_is_symbol(t1)) f_lib = ((jl_sym_t*)t1)->name; else if (jl_is_byte_string(t1)) f_lib = jl_string_data(t1); else JL_TYPECHK(ccall, symbol, t1); } else { JL_TYPECHK(ccall, pointer, ptr); } } if (f_name == NULL && fptr == NULL && jl_ptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); } JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, tuple, at); JL_TYPECHK(ccall, type, at); jl_tuple_t *tt = (jl_tuple_t*)at; std::vector<Type *> fargt(0); std::vector<Type *> fargt_sig(0); Type *lrt = julia_type_to_llvm(rt); if (lrt == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } size_t i; bool haspointers = false; bool isVa = false; size_t nargt = jl_tuple_len(tt); std::vector<AttributeWithIndex> attrs; for(i=0; i < nargt; i++) { jl_value_t *tti = jl_tupleref(tt,i); if (jl_is_vararg_type(tti)) { isVa = true; tti = jl_tparam0(tti); } if (jl_is_bits_type(tti)) { // see pull req #978. need to annotate signext/zeroext for // small integer arguments. jl_bits_type_t *bt = (jl_bits_type_t*)tti; if (bt->nbits < 32) { if (jl_signed_type == NULL) { jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); } #ifdef LLVM32 Attributes::AttrVal av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attributes::SExt; else av = Attributes::ZExt; attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1, ArrayRef<Attributes::AttrVal>(&av, 1))); #else Attribute::AttrConst av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attribute::SExt; else av = Attribute::ZExt; attrs.push_back(AttributeWithIndex::get(i+1, av)); #endif } } Type *t = julia_type_to_llvm(tti); if (t == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) fargt_sig.push_back(t); } // check for calling convention specifier CallingConv::ID cc = CallingConv::C; jl_value_t *last = args[nargs]; if (jl_is_expr(last)) { jl_sym_t *lhd = ((jl_expr_t*)last)->head; if (lhd == jl_symbol("stdcall")) { cc = CallingConv::X86_StdCall; nargs--; } else if (lhd == jl_symbol("cdecl")) { cc = CallingConv::C; nargs--; } else if (lhd == jl_symbol("fastcall")) { cc = CallingConv::X86_FastCall; nargs--; } else if (lhd == jl_symbol("thiscall")) { cc = CallingConv::X86_ThisCall; nargs--; } } if ((!isVa && jl_tuple_len(tt) != (nargs-2)/2) || ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2)) jl_error("ccall: wrong number of arguments to C function"); // some special functions if (fptr == &jl_array_ptr) { Value *ary = emit_expr(args[4], ctx); JL_GC_POP(); return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt), rt); } // see if there are & arguments for(i=4; i < nargs+1; i+=2) { jl_value_t *argi = args[i]; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { haspointers = true; break; } } // make LLVM function object for the target Value *llvmf; FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); if (jl_ptr != NULL) { null_pointer_check(jl_ptr,ctx); Type *funcptype = PointerType::get(functype,0); llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); } else if (fptr != NULL) { Type *funcptype = PointerType::get(functype,0); llvmf = literal_pointer_val(fptr, funcptype); } else { void *symaddr; if (f_lib != NULL) symaddr = add_library_sym(f_name, f_lib); else symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); if (symaddr == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: could not find function "; msg << f_name; if (f_lib != NULL) { msg << " in library "; msg << f_lib; } emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } llvmf = jl_Module->getOrInsertFunction(f_name, functype); } // save temp argument area stack pointer Value *saveloc=NULL; Value *stacksave=NULL; if (haspointers) { // TODO: inline this saveloc = builder.CreateCall(save_arg_area_loc_func); stacksave = builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); } // emit arguments Value *argvals[(nargs-3)/2]; int last_depth = ctx->argDepth; int nargty = jl_tuple_len(tt); for(i=4; i < nargs+1; i+=2) { int ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Type *largty; jl_value_t *jargty; if (isVa && ai >= nargty-1) { largty = fargt[nargty-1]; jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); } else { largty = fargt[ai]; jargty = jl_tupleref(tt,ai); } Value *arg; if (largty == jl_pvalue_llvmt) { arg = emit_expr(argi, ctx, true); } else { arg = emit_unboxed(argi, ctx); if (jl_is_bits_type(expr_type(argi, ctx))) { if (addressOf) arg = emit_unbox(largty->getContainedType(0), largty, arg); else arg = emit_unbox(largty, PointerType::get(largty,0), arg); } } /* #ifdef JL_GC_MARKSWEEP // make sure args are rooted if (largty->isPointerTy() && (largty == jl_pvalue_llvmt || !jl_is_bits_type(expr_type(args[i], ctx)))) { make_gcroot(boxed(arg), ctx); } #endif */ argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf, ai+1, ctx); } // the actual call Value *result = builder.CreateCall(llvmf, ArrayRef<Value*>(&argvals[0],(nargs-3)/2)); if (cc != CallingConv::C) ((CallInst*)result)->setCallingConv(cc); #ifdef LLVM32 ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs))); #else ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size())); #endif // restore temp argument area stack pointer if (haspointers) { assert(saveloc != NULL); builder.CreateCall(restore_arg_area_loc_func, saveloc); assert(stacksave != NULL); builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stackrestore), stacksave); } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #ifdef LLVM32 ctx->f->addFnAttr(Attributes::StackProtectReq); #else ctx->f->addFnAttr(Attribute::StackProtectReq); #endif } JL_GC_POP(); if (lrt == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); return mark_julia_type(result, rt); }
Value *CodeGen::generateNumber(int value){ return ConstantInt::get( Type::getInt32Ty(getGlobalContext()), value); }
static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_name, jl_codectx_t *ctx) { // in pseudo-code, this function emits the following: // global uv_lib_t **libptrgv // global void **llvmgv // if (*llvmgv == NULL) { // *llvmgv = jl_load_and_lookup(f_lib, f_name, libptrgv); // } // return (*llvmgv) Constant *initnul = ConstantPointerNull::get((PointerType*)T_pint8); uv_lib_t *libsym = NULL; bool runtime_lib = false; GlobalVariable *libptrgv; #ifdef _OS_WINDOWS_ if ((intptr_t)f_lib == 1) libptrgv = jlexe_var; else if ((intptr_t)f_lib == 2) libptrgv = jldll_var; else #endif if (f_lib == NULL) { libptrgv = jlRTLD_DEFAULT_var; } else { runtime_lib = true; libptrgv = libMapGV[f_lib]; if (libptrgv == NULL) { libptrgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, f_lib); libMapGV[f_lib] = libptrgv; libsym = get_library(f_lib); *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)) = libsym; } } if (libsym == NULL) { libsym = *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)); } GlobalVariable *llvmgv = symMapGV[f_name]; if (llvmgv == NULL) { llvmgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, f_name); symMapGV[f_name] = llvmgv; *((void**)jl_ExecutionEngine->getPointerToGlobal(llvmgv)) = jl_dlsym_e(libsym, f_name); } BasicBlock *dlsym_lookup = BasicBlock::Create(getGlobalContext(), "dlsym"), *ccall_bb = BasicBlock::Create(getGlobalContext(), "ccall"); builder.CreateCondBr(builder.CreateICmpNE(builder.CreateLoad(llvmgv), initnul), ccall_bb, dlsym_lookup); ctx->f->getBasicBlockList().push_back(dlsym_lookup); builder.SetInsertPoint(dlsym_lookup); Value *libname; if (runtime_lib) { libname = builder.CreateGlobalStringPtr(f_lib); } else { libname = literal_static_pointer_val(f_lib, T_pint8); } Value *llvmf = builder.CreateCall3(jldlsym_func, libname, builder.CreateGlobalStringPtr(f_name), libptrgv); builder.CreateStore(llvmf, llvmgv); builder.CreateBr(ccall_bb); ctx->f->getBasicBlockList().push_back(ccall_bb); builder.SetInsertPoint(ccall_bb); llvmf = builder.CreateLoad(llvmgv); return builder.CreatePointerCast(llvmf,funcptype); }
/// HandleArgument - This is invoked by the target-independent code for each /// argument type passed into the function. It potentially breaks down the /// argument and invokes methods on the client that indicate how its pieces /// should be handled. This handles things like decimating structures into /// their fields. void DefaultABI::HandleArgument(tree type, std::vector<const Type*> &ScalarElts, Attributes *Attributes) { unsigned Size = 0; bool DontCheckAlignment = false; const Type *Ty = ConvertType(type); // Figure out if this field is zero bits wide, e.g. {} or [0 x int]. Do // not include variable sized fields here. std::vector<const Type*> Elts; if (Ty->isVoidTy()) { // Handle void explicitly as an opaque type. const Type *OpTy = OpaqueType::get(getGlobalContext()); C.HandleScalarArgument(OpTy, type); ScalarElts.push_back(OpTy); } else if (isPassedByInvisibleReference(type)) { // variable size -> by-ref. const Type *PtrTy = Ty->getPointerTo(); C.HandleByInvisibleReferenceArgument(PtrTy, type); ScalarElts.push_back(PtrTy); } else if (Ty->isVectorTy()) { if (LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(type)) { PassInIntegerRegisters(type, ScalarElts, 0, false); } else if (LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR(type)) { C.HandleByValArgument(Ty, type); if (Attributes) { *Attributes |= Attribute::ByVal; *Attributes |= Attribute::constructAlignmentFromInt(LLVM_BYVAL_ALIGNMENT(type)); } } else { C.HandleScalarArgument(Ty, type); ScalarElts.push_back(Ty); } } else if (LLVM_TRY_PASS_AGGREGATE_CUSTOM(type, ScalarElts, C.getCallingConv(), &C)) { // Nothing to do. } else if (Ty->isSingleValueType()) { C.HandleScalarArgument(Ty, type); ScalarElts.push_back(Ty); } else if (LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(type, Ty)) { C.HandleFCAArgument(Ty, type); } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, C.getCallingConv(), Elts)) { if (!LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Elts, ScalarElts, C.isShadowReturn(), C.getCallingConv())) PassInMixedRegisters(Ty, Elts, ScalarElts); else { C.HandleByValArgument(Ty, type); if (Attributes) { *Attributes |= Attribute::ByVal; *Attributes |= Attribute::constructAlignmentFromInt(LLVM_BYVAL_ALIGNMENT(type)); } } } else if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty)) { C.HandleByValArgument(Ty, type); if (Attributes) { *Attributes |= Attribute::ByVal; *Attributes |= Attribute::constructAlignmentFromInt(LLVM_BYVAL_ALIGNMENT(type)); } } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type, &Size, &DontCheckAlignment)) { PassInIntegerRegisters(type, ScalarElts, Size, DontCheckAlignment); } else if (isZeroSizedStructOrUnion(type)) { // Zero sized struct or union, just drop it! ; } else if (TREE_CODE(type) == RECORD_TYPE) { for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) if (TREE_CODE(Field) == FIELD_DECL) { const tree Ftype = getDeclaredType(Field); const Type *FTy = ConvertType(Ftype); unsigned FNo = GET_LLVM_FIELD_INDEX(Field); assert(FNo != ~0U && "Case not handled yet!"); // Currently, a bvyal type inside a non-byval struct is a zero-length // object inside a bigger object on x86-64. This type should be // skipped (but only when it is inside a bigger object). // (We know there currently are no other such cases active because // they would hit the assert in FunctionPrologArgumentConversion:: // HandleByValArgument.) if (!LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(Ftype, FTy)) { C.EnterField(FNo, Ty); HandleArgument(getDeclaredType(Field), ScalarElts); C.ExitField(); } } } else if (TREE_CODE(type) == COMPLEX_TYPE) { C.EnterField(0, Ty); HandleArgument(TREE_TYPE(type), ScalarElts); C.ExitField(); C.EnterField(1, Ty); HandleArgument(TREE_TYPE(type), ScalarElts); C.ExitField(); } else if ((TREE_CODE(type) == UNION_TYPE) || (TREE_CODE(type) == QUAL_UNION_TYPE)) { HandleUnion(type, ScalarElts); } else if (TREE_CODE(type) == ARRAY_TYPE) { const ArrayType *ATy = cast<ArrayType>(Ty); for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) { C.EnterField(i, Ty); HandleArgument(TREE_TYPE(type), ScalarElts); C.ExitField(); } } else { assert(0 && "unknown aggregate type!"); abort(); } }
void *LLVMFormula::emit (NumberExprAST *expr) { return ConstantFP::get (getGlobalContext (), APFloat (expr->val)); }
void Executor::callUnmodelledFunction(ExecutionState &state, KInstruction *target, llvm::Function *function, std::vector<ref<Expr> > &arguments) { if (NoExternals && !okExternals.count(function->getName())) { std::cerr << "KLEE:ERROR: Calling not-OK external function : " << function->getName().str() << "\n"; terminateStateOnError(state, "externals disallowed", "user.err"); return; } // normal external function handling path // allocate 128 bits for each argument (+return value) to support fp80's; // we could iterate through all the arguments first and determine the exact // size we need, but this is faster, and the memory usage isn't significant. uint64_t *args = (uint64_t*) alloca(2*sizeof(*args) * (arguments.size() + 1)); memset(args, 0, 2 * sizeof(*args) * (arguments.size() + 1)); unsigned wordIndex = 2; for (std::vector<ref<Expr> >::iterator ai = arguments.begin(), ae = arguments.end(); ai!=ae; ++ai) { if (AllowExternalSymCalls) { // don't bother checking uniqueness ref<ConstantExpr> ce; bool success = solver->getValue(data::EXTERNAL_CALL_CONCRETIZATION, state, *ai, ce); assert(success && "FIXME: Unhandled solver failure"); (void) success; ce->toMemory(&args[wordIndex]); wordIndex += (ce->getWidth()+63)/64; } else { ref<Expr> arg = toUnique(state, *ai); if (ConstantExpr *ce = dyn_cast<ConstantExpr>(arg)) { // XXX kick toMemory functions from here ce->toMemory(&args[wordIndex]); wordIndex += (ce->getWidth()+63)/64; } else { terminateStateOnExecError(state, "external call with symbolic argument: " + function->getName()); return; } } } state.addressSpace().copyOutConcretes(&state.addressPool); if (!SuppressExternalWarnings) { std::ostringstream os; os << state << " Calling external: " << function->getName().str() << "("; for (unsigned i=0; i<arguments.size(); i++) { os << arguments[i]; if (i != arguments.size()-1) os << ", "; } os << ")"; VLOG(1) << os.str().c_str(); } bool success = externalDispatcher->executeCall(function, target->inst, args); if (!success) { terminateStateOnError(state, "failed external call: " + function->getName(), "external.err"); return; } if (!state.addressSpace().copyInConcretes(&state.addressPool)) { terminateStateOnError(state, "external modified read-only object", "external.err"); return; } Type *resultType = target->inst->getType(); if (resultType != Type::getVoidTy(getGlobalContext())) { ref<Expr> e = ConstantExpr::fromMemory((void*) args, getWidthForLLVMType(resultType)); bindLocal(target, state, e); } }
/// PassInIntegerRegisters - Given an aggregate value that should be passed in /// integer registers, convert it to a structure containing ints and pass all /// of the struct elements in. If Size is set we pass only that many bytes. void DefaultABI::PassInIntegerRegisters(tree type, std::vector<const Type*> &ScalarElts, unsigned origSize, bool DontCheckAlignment) { unsigned Size; if (origSize) Size = origSize; else Size = TREE_INT_CST_LOW(TYPE_SIZE(type))/8; // FIXME: We should preserve all aggregate value alignment information. // Work around to preserve some aggregate value alignment information: // don't bitcast aggregate value to Int64 if its alignment is different // from Int64 alignment. ARM backend needs this. unsigned Align = TYPE_ALIGN(type)/8; unsigned Int64Align = getTargetData().getABITypeAlignment(Type::getInt64Ty(getGlobalContext())); bool UseInt64 = (DontCheckAlignment || Align >= Int64Align); unsigned ElementSize = UseInt64 ? 8:4; unsigned ArraySize = Size / ElementSize; // Put as much of the aggregate as possible into an array. const Type *ATy = NULL; const Type *ArrayElementType = NULL; if (ArraySize) { Size = Size % ElementSize; ArrayElementType = (UseInt64 ? Type::getInt64Ty(getGlobalContext()) : Type::getInt32Ty(getGlobalContext())); ATy = ArrayType::get(ArrayElementType, ArraySize); } // Pass any leftover bytes as a separate element following the array. unsigned LastEltRealSize = 0; const llvm::Type *LastEltTy = 0; if (Size > 4) { LastEltTy = Type::getInt64Ty(getGlobalContext()); } else if (Size > 2) { LastEltTy = Type::getInt32Ty(getGlobalContext()); } else if (Size > 1) { LastEltTy = Type::getInt16Ty(getGlobalContext()); } else if (Size > 0) { LastEltTy = Type::getInt8Ty(getGlobalContext()); } if (LastEltTy) { if (Size != getTargetData().getTypeAllocSize(LastEltTy)) LastEltRealSize = Size; } std::vector<const Type*> Elts; if (ATy) Elts.push_back(ATy); if (LastEltTy) Elts.push_back(LastEltTy); const StructType *STy = StructType::get(getGlobalContext(), Elts, false); unsigned i = 0; if (ArraySize) { C.EnterField(0, STy); for (unsigned j = 0; j < ArraySize; ++j) { C.EnterField(j, ATy); C.HandleScalarArgument(ArrayElementType, 0); ScalarElts.push_back(ArrayElementType); C.ExitField(); } C.ExitField(); ++i; } if (LastEltTy) { C.EnterField(i, STy); C.HandleScalarArgument(LastEltTy, 0, LastEltRealSize); ScalarElts.push_back(LastEltTy); C.ExitField(); } }
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //===----------------------------------------------------------------------===// // This is a C++ source file that implements specific llvm mips ABI. //===----------------------------------------------------------------------===// #include "llvm-abi.h" #include "llvm-mips-target.h" static LLVMContext &Context = getGlobalContext(); /* Target hook for llvm-abi.h. It returns true if an aggregate of the specified type should be passed in memory. In mips EABI this is true for aggregates with size > 32-bits. */ bool llvm_mips_should_pass_aggregate_in_memory(tree TreeType, Type *Ty) { if (mips_abi == ABI_EABI) { enum machine_mode mode = TYPE_MODE(TreeType); int size; if (mode == DImode || mode == DFmode) return false; size = TreeType ? int_size_in_bytes (TreeType) : GET_MODE_SIZE (mode); return size == -1 || size > UNITS_PER_WORD;
Parser::Parser(const std::shared_ptr<Module> &module) : _inputTag(nullptr), _builder(getGlobalContext()) { _lastChar = ' '; _module = module; }
bool CompiledCondition::compile(){ InitializeNativeTarget(); // Assume we're on main thread... LLVMContext &context = getGlobalContext(); // Initialize module Module* module = new Module("Compiled function", context); // Create exection engine ExecutionEngine* engine = EngineBuilder(module).create(); /********** Generate code **********/ //Get a type for representing an integer pointer //Maybe this should be unsigned integer pointer type... PointerType* integerPointerType = PointerType::get(IntegerType::get(module->getContext(), 32), 0); //Create function type, for our function, int*, int* -> bool vector<const Type*> paramType; paramType.push_back(integerPointerType); paramType.push_back(integerPointerType); FunctionType* functionType = FunctionType::get(IntegerType::get(module->getContext(), 8), paramType, false); //Declare new function Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "evaluate", module); //Use C calling convention function->setCallingConv(CallingConv::C); //TODO: Read documentation and reconsider this //Get arguments from function Function::arg_iterator args = function->arg_begin(); Value* marking = args++; Value* valuation = args++; marking->setName("marking"); valuation->setName("valuation"); //Create function block BasicBlock* functionBlock = BasicBlock::Create(module->getContext(), "functionBlock", function, 0); //Generate code CodeGenerationContext codeGenContext(marking, valuation, functionBlock, context); Value* result = _cond->codegen(codeGenContext); //Zero extend the result, e.g. make it a 8 bit bool CastInst* retval = new ZExtInst(result, IntegerType::get(module->getContext(), 8), "retval", functionBlock); //Create a return instruction ReturnInst::Create(module->getContext(), retval, functionBlock); /********** Optimize and Compile **********/ // Create function pass manager, to optimize query FunctionPassManager optimizer(module); optimizer.add(new TargetData(*engine->getTargetData())); optimizer.add(createBasicAliasAnalysisPass()); optimizer.add(createInstructionCombiningPass()); optimizer.add(createReassociatePass()); optimizer.add(createGVNPass()); optimizer.add(createCFGSimplificationPass()); optimizer.doInitialization(); // Verify function, errors written to stderr if(verifyFunction(*function)) return false; // Optimize function optimizer.run(*function); // Compile the function _nativeFunction = (bool(*)(const MarkVal*, const VarVal*))engine->getPointerToFunction(function); return _nativeFunction != NULL; }
static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, jl_value_t *aty, bool addressOf, bool byRef, bool inReg, bool needCopy, int argn, jl_codectx_t *ctx, bool *needStackRestore) { Type *vt = jv->getType(); // We're passing any if (ty == jl_pvalue_llvmt) { return boxed(jv,ctx); } if (ty == vt && !addressOf && !byRef) { return jv; } if (vt != jl_pvalue_llvmt) { // argument value is unboxed if (addressOf || (byRef && inReg)) { if (ty->isPointerTy() && ty->getContainedType(0)==vt) { // pass the address of an alloca'd thing, not a box // since those are immutable. *needStackRestore = true; Value *slot = builder.CreateAlloca(vt); builder.CreateStore(jv, slot); return builder.CreateBitCast(slot, ty); } } else if ((vt->isIntegerTy() && ty->isIntegerTy()) || (vt->isFloatingPointTy() && ty->isFloatingPointTy()) || (vt->isPointerTy() && ty->isPointerTy())) { if (vt->getPrimitiveSizeInBits() == ty->getPrimitiveSizeInBits()) { if (!byRef) { return builder.CreateBitCast(jv, ty); } else { *needStackRestore = true; Value *mem = builder.CreateAlloca(ty); builder.CreateStore(jv,builder.CreateBitCast(mem,vt->getPointerTo())); return mem; } } } else if (vt->isStructTy()) { if (!byRef) { return jv; } else { *needStackRestore = true; Value *mem = builder.CreateAlloca(vt); builder.CreateStore(jv,mem); return mem; } } emit_error("ccall: argument type did not match declaration", ctx); } if (jl_is_tuple(jt)) { return emit_unbox(ty,jv,jt); } if (jl_is_cpointer_type(jt) && addressOf) { assert(ty->isPointerTy()); jl_value_t *ety = jl_tparam0(jt); if (aty != ety && ety != (jl_value_t*)jl_any_type && jt != (jl_value_t*)jl_voidpointer_type) { std::stringstream msg; msg << "ccall argument "; msg << argn; emit_typecheck(jv, ety, msg.str(), ctx); } if (jl_is_mutable_datatype(ety)) { // no copy, just reference the data field return builder.CreateBitCast(jv, ty); } else if (jl_is_immutable_datatype(ety) && jt != (jl_value_t*)jl_voidpointer_type) { // yes copy Value *nbytes; if (jl_is_leaf_type(ety)) nbytes = ConstantInt::get(T_int32, jl_datatype_size(ety)); else nbytes = tbaa_decorate(tbaa_datatype, builder.CreateLoad( builder.CreateGEP(builder.CreatePointerCast(emit_typeof(jv), T_pint32), ConstantInt::get(T_size, offsetof(jl_datatype_t,size)/sizeof(int32_t))), false)); *needStackRestore = true; AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes); ai->setAlignment(16); builder.CreateMemCpy(ai, builder.CreateBitCast(jv, T_pint8), nbytes, 1); return builder.CreateBitCast(ai, ty); } // emit maybe copy *needStackRestore = true; Value *jvt = emit_typeof(jv); BasicBlock *mutableBB = BasicBlock::Create(getGlobalContext(),"is-mutable",ctx->f); BasicBlock *immutableBB = BasicBlock::Create(getGlobalContext(),"is-immutable",ctx->f); BasicBlock *afterBB = BasicBlock::Create(getGlobalContext(),"after",ctx->f); Value *ismutable = builder.CreateTrunc( tbaa_decorate(tbaa_datatype, builder.CreateLoad( builder.CreateGEP(builder.CreatePointerCast(jvt, T_pint8), ConstantInt::get(T_size, offsetof(jl_datatype_t,mutabl))), false)), T_int1); builder.CreateCondBr(ismutable, mutableBB, immutableBB); builder.SetInsertPoint(mutableBB); Value *p1 = builder.CreatePointerCast(jv, ty); builder.CreateBr(afterBB); builder.SetInsertPoint(immutableBB); Value *nbytes = tbaa_decorate(tbaa_datatype, builder.CreateLoad( builder.CreateGEP(builder.CreatePointerCast(jvt, T_pint32), ConstantInt::get(T_size, offsetof(jl_datatype_t,size)/sizeof(int32_t))), false)); AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes); ai->setAlignment(16); builder.CreateMemCpy(ai, builder.CreatePointerCast(jv, T_pint8), nbytes, 1); Value *p2 = builder.CreatePointerCast(ai, ty); builder.CreateBr(afterBB); builder.SetInsertPoint(afterBB); PHINode *p = builder.CreatePHI(ty, 2); p->addIncoming(p1, mutableBB); p->addIncoming(p2, immutableBB); return p; } if (addressOf) jl_error("ccall: unexpected & on argument"); // the only "safe" thing to emit here is the expected struct assert(jl_is_datatype(jt)); if (aty != jt) { std::stringstream msg; msg << "ccall argument "; msg << argn; emit_typecheck(jv, jt, msg.str(), ctx); } Value *p = data_pointer(jv); Value *pjv = builder.CreatePointerCast(p, PointerType::get(ty,0)); if (byRef) { if (!needCopy) { return pjv; } else { *needStackRestore = true; Value *mem = builder.CreateAlloca(ty); builder.CreateMemCpy(mem,pjv,(uint64_t)jl_datatype_size(jt),(uint64_t)((jl_datatype_t*)jt)->alignment); return mem; } } else { return builder.CreateLoad(pjv,false); } }
void *LLVMFormula::emit (BinaryExprAST *expr) { if (expr->op == "=") { // The assign function has to be dealt with specially, we *do not* // want to emit the LHS code (the load-from-memory instruction)! VariableExprAST *var = dynamic_cast<VariableExprAST *>(expr->LHS); if (!var) return NULL; Value *val = (Value *)expr->RHS->generate (this); if (!val) return NULL; // Emit a store-to-pointer instruction builder->CreateStore (val, getGlobalVariableFor (var->pointer), "storetmp"); return val; } // The rest of the operators function normally Value *L = (Value *)expr->LHS->generate (this); Value *R = (Value *)expr->RHS->generate (this); if (L == NULL || R == NULL) return NULL; if (expr->op == "<=") { L = builder->CreateFCmpULE (L, R, "letmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == ">=") { L = builder->CreateFCmpUGE (L, R, "getmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == "!=") { L = builder->CreateFCmpUNE (L, R, "neqtmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == "==") { L = builder->CreateFCmpUEQ (L, R, "eqtmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == "<") { L = builder->CreateFCmpULT (L, R, "lttmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == ">") { L = builder->CreateFCmpUGT (L, R, "gttmp"); return builder->CreateUIToFP (L, Type::getDoubleTy (getGlobalContext ()), "booltmp"); } else if (expr->op == "+") return builder->CreateFAdd (L, R, "addtmp"); else if (expr->op == "-") return builder->CreateFSub (L, R, "subtmp"); else if (expr->op == "*") return builder->CreateFMul (L, R, "multmp"); else if (expr->op == "/") return builder->CreateFDiv (L, R, "divtmp"); else if (expr->op == "^") { // The floating-point intrinsics are overloaded for multiple types Type *types[1] = { Type::getDoubleTy (getGlobalContext ()) }; ArrayRef<Type *> type_array(types, 1); Value *func = Intrinsic::getDeclaration (module, Intrinsic::pow, type_array); return builder->CreateCall2 (func, L, R, "pow"); } else return NULL; }
/** * Module取得 */ Module &CodeGen::getModule(){ if(Mod) return *Mod; else return *(new Module("null", getGlobalContext())); }
void *LLVMFormula::emit (CallExprAST *expr) { // Deal with the if-instruction first, specially if (expr->function == "if") { Value *cond = (Value *)expr->args[0]->generate (this); Value *t = (Value *)expr->args[1]->generate (this); Value *f = (Value *)expr->args[2]->generate (this); if (cond == NULL || t == NULL || f == NULL) return NULL; Value *one = ConstantFP::get (getGlobalContext (), APFloat (1.0)); Value *cmp = builder->CreateFCmpOEQ (cond, one, "ifcmptmp"); return builder->CreateSelect (cmp, t, f, "ifelsetmp"); } // Sign isn't a standard-library function, implement it with a compare if (expr->function == "sign") { Value *v = (Value *)expr->args[0]->generate (this); if (!v) return NULL; Value *zero = ConstantFP::get (getGlobalContext (), APFloat (0.0)); Value *one = ConstantFP::get (getGlobalContext (), APFloat (1.0)); Value *none = ConstantFP::get (getGlobalContext (), APFloat (-1.0)); Value *cmpgzero = builder->CreateFCmpOGT (v, zero, "sgncmpgzero"); Value *cmplzero = builder->CreateFCmpOLT (v, zero, "sgncmplzero"); Value *fselect = builder->CreateSelect (cmplzero, none, zero, "sgnsellzero"); return builder->CreateSelect (cmpgzero, one, fselect, "sgnselgzero"); } // // Map our function names to standard libm names // // If we're calling "log", we want "log10" if (expr->function == "log") expr->function = "log10"; // If we're calling "ln", we want "log" if (expr->function == "ln") expr->function = "log"; // If we're calling "abs", we want "fabs" if (expr->function == "abs") expr->function = "fabs"; // The following are available as LLVM intrinsics, and we should emit them // specially without calling out to libm: Intrinsic::ID intrinsicID = Intrinsic::not_intrinsic; if (expr->function == "cos") intrinsicID = Intrinsic::cos; else if (expr->function == "exp") intrinsicID = Intrinsic::exp; else if (expr->function == "log") intrinsicID = Intrinsic::log; else if (expr->function == "log10") intrinsicID = Intrinsic::log10; else if (expr->function == "sin") intrinsicID = Intrinsic::sin; else if (expr->function == "sqrt") intrinsicID = Intrinsic::sqrt; if (intrinsicID != Intrinsic::not_intrinsic) { // Most of the floating-point intrinsics are overloaded for multiple types Type *types[1] = { Type::getDoubleTy (getGlobalContext ()) }; ArrayRef<Type *> type_array(types, 1); Value *arg = (Value *)expr->args[0]->generate (this); if (!arg) return NULL; Value *func = Intrinsic::getDeclaration (module, intrinsicID, type_array); return builder->CreateCall (func, arg, expr->function); } // The rest of these are calls to stdlib floating point math // functions. // atan2 is special, because it has two arguments if (expr->function == "atan2") { Value *arg1 = (Value *)expr->args[0]->generate (this); Value *arg2 = (Value *)expr->args[1]->generate (this); if (!arg1 || !arg2) return NULL; Module *M = builder->GetInsertBlock ()->getParent ()->getParent (); Value *Callee = M->getOrInsertFunction (expr->function, Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), NULL); return builder->CreateCall2 (Callee, arg1, arg2, expr->function); } else { // Emit a call to function (arg) Value *arg = (Value *)expr->args[0]->generate (this); if (!arg) return NULL; Module *M = builder->GetInsertBlock ()->getParent ()->getParent (); Value *Callee = M->getOrInsertFunction (expr->function, Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), NULL); return builder->CreateCall (Callee, arg, expr->function); } }
/** * コンストラクタ */ CodeGen::CodeGen(){ Builder = new IRBuilder<>(getGlobalContext()); }
// ============================================================================= // replaceCallsInProcess // // Replace indirect calls to write() or read() by direct calls // in the given process. // ============================================================================= void TLMBasicPassImpl::replaceCallsInProcess(sc_core::sc_module *initiatorMod, sc_core::sc_process_b *proc) { // Get associate function std::string fctName = proc->func_process; std::string modType = typeid(*initiatorMod).name(); std::string mainFctName = "_ZN" + modType + utostr(fctName.size()) + fctName + "Ev"; Function *oldProcf = this->llvmMod->getFunction(mainFctName); if (oldProcf==NULL) return; // We do not modifie the original function // Instead, we create a clone. Function *procf = createProcess(oldProcf, initiatorMod); void *funPtr = this->engine->getPointerToFunction(procf); sc_core::SC_ENTRY_FUNC_OPT scfun = reinterpret_cast<sc_core::SC_ENTRY_FUNC_OPT>(funPtr); proc->m_semantics_p = scfun; std::string procfName = procf->getName(); MSG(" Replace in the process's function : "+procfName+"\n"); std::ostringstream oss; sc_core::sc_module *targetMod; std::vector<CallInfo*> *work = new std::vector<CallInfo*>; inst_iterator ii; for (ii = inst_begin(procf); ii!=inst_end(procf); ii++) { Instruction &i = *ii; CallSite cs(&i); if (cs.getInstruction()) { // Candidate for a replacement Function *oldfun = cs.getCalledFunction(); if (oldfun!=NULL && !oldfun->isDeclaration()) { std::string name = oldfun->getName(); // === Write === if (!strcmp(name.c_str(), wFunName.c_str())) { CallInfo *info = new CallInfo(); info->oldcall = dyn_cast<CallInst>(cs.getInstruction()); MSG(" Checking adress : "); // Retrieve the adress argument by executing // the appropriated piece of code SCJit *scjit = new SCJit(this->llvmMod, this->elab); Process *irProc = this->elab->getProcess(proc); scjit->setCurrentProcess(irProc); bool jitErr = false; info->addrArg = cs.getArgument(1); int value = scjit->jitInt(procf, info->oldcall, info->addrArg, &jitErr); if(jitErr) { std::cout << " cannot get the address value!" << std::endl; } else { oss.str(""); oss << std::hex << value; MSG("0x"+oss.str()+"\n"); basic::addr_t a = static_cast<basic::addr_t>(value); // Checking address alignment if(value % sizeof(basic::data_t)) { std::cerr << " unaligned write : " << std::hex << value << std::endl; abort(); } // Retreive the target module using the address targetMod = getTargetModule(initiatorMod, a); // Save informations to build a new call later FunctionType *writeFunType = this->basicWriteFun->getFunctionType(); info->targetType = writeFunType->getParamType(0); LLVMContext &context = getGlobalContext(); IntegerType *intType; if (this->is64Bit) { intType = Type::getInt64Ty(context); } else { intType = Type::getInt32Ty(context); } info->targetModVal = ConstantInt::getSigned(intType, reinterpret_cast<intptr_t>(targetMod)); info->dataArg = cs.getArgument(2); work->push_back(info); } } else // === Read === if (!strcmp(name.c_str(), rFunName.c_str())) { // Not yet supported } } } } // Before //procf->dump(); // Replace calls std::vector<CallInfo*>::iterator it; for (it = work->begin(); it!=work->end(); ++it) { CallInfo *i = *it; LLVMContext &context = getGlobalContext(); FunctionType *writeFunType = this->writeFun->getFunctionType(); IntegerType *i64 = Type::getInt64Ty(context); // Get a pointer to the target module basic::target_module_base *tmb = dynamic_cast<basic::target_module_base*>(targetMod); Value *ptr = ConstantInt::getSigned(i64, reinterpret_cast<intptr_t>(tmb)); IntToPtrInst *modPtr = new IntToPtrInst(ptr, writeFunType->getParamType(0), "myitp", i->oldcall); // Get a the address value LoadInst *addr = new LoadInst(i->addrArg, "", i->oldcall); // Create the new call Value *args[] = {modPtr, addr, i->dataArg}; i->newcall = CallInst::Create(this->writeFun, ArrayRef<Value*>(args, 3)); // Replace the old call BasicBlock::iterator it(i->oldcall); ReplaceInstWithInst(i->oldcall->getParent()->getInstList(), it, i->newcall); i->oldcall->replaceAllUsesWith(i->newcall); // Inline the new call DataLayout *td = new DataLayout(this->llvmMod); InlineFunctionInfo ifi(NULL, td); bool success = InlineFunction(i->newcall, ifi); if(!success) { MSG(" The call cannot be inlined (it's not an error :D)"); } MSG(" Call optimized (^_-)\n"); callOptCounter++; } //std::cout << "==================================\n"; // Run preloaded passes on the function to propagate constants funPassManager->run(*procf); // After //procf->dump(); // Check if the function is corrupt verifyFunction(*procf); this->engine->recompileAndRelinkFunction(procf); }
// ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { JL_NARGSV(ccall, 3); jl_value_t *rt=NULL, *at=NULL; JL_GC_PUSH2(&rt, &at); native_sym_arg_t symarg = interpret_symbol_arg(args[1], ctx, "ccall"); Value *jl_ptr=NULL; void *fptr = NULL; char *f_name = NULL, *f_lib = NULL; jl_ptr = symarg.jl_ptr; fptr = symarg.fptr; f_name = symarg.f_name; f_lib = symarg.f_lib; if (f_name == NULL && fptr == NULL && jl_ptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); } rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); if (jl_is_tuple(rt)) { std::string msg = "in " + ctx->funcName + ": ccall: missing return type"; jl_error(msg.c_str()); } if (rt == (jl_value_t*)jl_pointer_type) jl_error("ccall: return type Ptr should have an element type, Ptr{T}"); at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, tuple, at); JL_TYPECHK(ccall, type, at); jl_tuple_t *tt = (jl_tuple_t*)at; std::vector<Type *> fargt(0); std::vector<Type *> fargt_sig(0); Type *lrt = julia_struct_to_llvm(rt); if (lrt == NULL) { JL_GC_POP(); emit_error("ccall: return type doesn't correspond to a C type", ctx); return literal_pointer_val(jl_nothing); } size_t i; bool isVa = false; size_t nargt = jl_tuple_len(tt); std::vector<AttributeWithIndex> attrs; for(i=0; i < nargt; i++) { jl_value_t *tti = jl_tupleref(tt,i); if (tti == (jl_value_t*)jl_pointer_type) jl_error("ccall: argument type Ptr should have an element type, Ptr{T}"); if (jl_is_vararg_type(tti)) { isVa = true; tti = jl_tparam0(tti); } if (jl_is_bitstype(tti)) { // see pull req #978. need to annotate signext/zeroext for // small integer arguments. jl_datatype_t *bt = (jl_datatype_t*)tti; if (bt->size < 4) { if (jl_signed_type == NULL) { jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); } #ifdef LLVM32 Attributes::AttrVal av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attributes::SExt; else av = Attributes::ZExt; attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1, ArrayRef<Attributes::AttrVal>(&av, 1))); #else Attribute::AttrConst av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attribute::SExt; else av = Attribute::ZExt; attrs.push_back(AttributeWithIndex::get(i+1, av)); #endif } } Type *t = julia_struct_to_llvm(tti); if (t == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: the type of argument "; msg << i+1; msg << " doesn't correspond to a C type"; emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) fargt_sig.push_back(t); } // check for calling convention specifier CallingConv::ID cc = CallingConv::C; jl_value_t *last = args[nargs]; if (jl_is_expr(last)) { jl_sym_t *lhd = ((jl_expr_t*)last)->head; if (lhd == jl_symbol("stdcall")) { cc = CallingConv::X86_StdCall; nargs--; } else if (lhd == jl_symbol("cdecl")) { cc = CallingConv::C; nargs--; } else if (lhd == jl_symbol("fastcall")) { cc = CallingConv::X86_FastCall; nargs--; } else if (lhd == jl_symbol("thiscall")) { cc = CallingConv::X86_ThisCall; nargs--; } } if ((!isVa && jl_tuple_len(tt) != (nargs-2)/2) || ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2)) jl_error("ccall: wrong number of arguments to C function"); // some special functions if (fptr == &jl_array_ptr) { assert(lrt->isPointerTy()); Value *ary = emit_expr(args[4], ctx); JL_GC_POP(); return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt), rt); } if (fptr == &jl_value_ptr) { assert(lrt->isPointerTy()); jl_value_t *argi = args[4]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Value *ary = boxed(emit_expr(argi, ctx)); JL_GC_POP(); return mark_julia_type( builder.CreateBitCast(emit_nthptr_addr(ary, addressOf?1:0),lrt), rt); } // make LLVM function object for the target Value *llvmf; FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); if (jl_ptr != NULL) { null_pointer_check(jl_ptr,ctx); Type *funcptype = PointerType::get(functype,0); llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); } else if (fptr != NULL) { Type *funcptype = PointerType::get(functype,0); llvmf = literal_pointer_val(fptr, funcptype); } else { void *symaddr; if (f_lib != NULL) symaddr = add_library_sym(f_name, f_lib); else symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); if (symaddr == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: could not find function "; msg << f_name; if (f_lib != NULL) { msg << " in library "; msg << f_lib; } emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } llvmf = jl_Module->getOrInsertFunction(f_name, functype); } // save place before arguments, for possible insertion of temp arg // area saving code. Value *saveloc=NULL; Value *stacksave=NULL; BasicBlock::InstListType &instList = builder.GetInsertBlock()->getInstList(); Instruction *savespot; if (instList.empty()) { savespot = NULL; } else { // hey C++, there's this thing called pointers... Instruction &_savespot = builder.GetInsertBlock()->back(); savespot = &_savespot; } // emit arguments Value *argvals[(nargs-3)/2]; int last_depth = ctx->argDepth; int nargty = jl_tuple_len(tt); bool needTempSpace = false; for(i=4; i < nargs+1; i+=2) { int ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Type *largty; jl_value_t *jargty; if (isVa && ai >= nargty-1) { largty = fargt[nargty-1]; jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); } else { largty = fargt[ai]; jargty = jl_tupleref(tt,ai); } Value *arg; if (largty == jl_pvalue_llvmt || largty->isStructTy()) { arg = emit_expr(argi, ctx, true); } else { arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { if (addressOf) arg = emit_unbox(largty->getContainedType(0), largty, arg); else arg = emit_unbox(largty, PointerType::get(largty,0), arg); } } /* #ifdef JL_GC_MARKSWEEP // make sure args are rooted if (largty->isPointerTy() && (largty == jl_pvalue_llvmt || !jl_is_bits_type(expr_type(args[i], ctx)))) { make_gcroot(boxed(arg), ctx); } #endif */ bool mightNeed=false; argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf, ai+1, ctx, &mightNeed); needTempSpace |= mightNeed; } if (needTempSpace) { // save temp argument area stack pointer // TODO: inline this saveloc = CallInst::Create(save_arg_area_loc_func); stacksave = CallInst::Create(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); if (savespot) instList.insertAfter(savespot, (Instruction*)saveloc); else instList.push_front((Instruction*)saveloc); instList.insertAfter((Instruction*)saveloc, (Instruction*)stacksave); } // the actual call Value *result = builder.CreateCall(llvmf, ArrayRef<Value*>(&argvals[0],(nargs-3)/2)); if (cc != CallingConv::C) ((CallInst*)result)->setCallingConv(cc); #ifdef LLVM32 ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs))); #else ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size())); #endif if (needTempSpace) { // restore temp argument area stack pointer assert(saveloc != NULL); builder.CreateCall(restore_arg_area_loc_func, saveloc); assert(stacksave != NULL); builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stackrestore), stacksave); } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #ifdef LLVM32 ctx->f->addFnAttr(Attributes::StackProtectReq); #else ctx->f->addFnAttr(Attribute::StackProtectReq); #endif } JL_GC_POP(); if (lrt == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); if (lrt->isStructTy()) { //fprintf(stderr, "ccall rt: %s -> %s\n", f_name, ((jl_tag_type_t*)rt)->name->name->name); assert(jl_is_structtype(rt)); Value *strct = builder.CreateCall(jlallocobj_func, ConstantInt::get(T_size, sizeof(void*)+((jl_datatype_t*)rt)->size)); builder.CreateStore(literal_pointer_val((jl_value_t*)rt), emit_nthptr_addr(strct, (size_t)0)); builder.CreateStore(result, builder.CreateBitCast( emit_nthptr_addr(strct, (size_t)1), PointerType::get(lrt,0))); return mark_julia_type(strct, rt); } return mark_julia_type(result, rt); }
// ============================================================================= // createProcess // // Create a new function that contains a call to the old function. // We inline the call in order to clone the old function's implementation. // ============================================================================= Function *TLMBasicPassImpl::createProcess(Function *oldProc, sc_core::sc_module *initiatorMod) { LLVMContext &context = getGlobalContext(); IntegerType *intType; if (this->is64Bit) { intType = Type::getInt64Ty(context); } else { intType = Type::getInt32Ty(context); } // Retrieve a pointer to the initiator module ConstantInt *initiatorModVal = ConstantInt::getSigned(intType,reinterpret_cast<intptr_t>(initiatorMod)); FunctionType *funType = oldProc->getFunctionType(); Type *type = funType->getParamType(0); IntToPtrInst *thisAddr = new IntToPtrInst(initiatorModVal, type, ""); // Compute the type of the new function FunctionType *oldProcType = oldProc->getFunctionType(); Value **argsBegin = new Value*[1]; Value **argsEnd = argsBegin; *argsEnd++ = thisAddr; const unsigned argsSize = argsEnd-argsBegin; Value **args = argsBegin; assert(oldProcType->getNumParams()==argsSize); assert(!oldProc->isDeclaration()); std::vector<Type*> argTypes; for (unsigned i = 0; i!=argsSize; ++i) argTypes.push_back(oldProcType->getParamType(i)); FunctionType *newProcType = FunctionType::get(oldProc->getReturnType(), ArrayRef<Type*>(argTypes), false); // Create the new function std::ostringstream id; id << proc_counter++; std::string name = oldProc->getName().str()+std::string("_clone_")+id.str(); Function *newProc = Function::Create(newProcType, Function::ExternalLinkage, name, this->llvmMod); assert(newProc->empty()); newProc->addFnAttr(Attributes::InlineHint); { // Set name of newfunc arguments and complete args Function::arg_iterator nai = newProc->arg_begin(); Function::arg_iterator oai = oldProc->arg_begin(); for (unsigned i = 0; i!=argsSize; ++i, ++oai) { nai->setName(oai->getName()); args[i] = nai; ++nai; } assert(nai==newProc->arg_end()); assert(oai==oldProc->arg_end()); } // Create call to old function BasicBlock *bb = BasicBlock::Create(context, "entry", newProc); IRBuilder<> *irb = new IRBuilder<>(context); irb->SetInsertPoint(bb); CallInst *ci = irb->CreateCall(oldProc, ArrayRef<Value*>(argsBegin, argsEnd)); bb->getInstList().insert(ci, thisAddr); if (ci->getType()->isVoidTy()) irb->CreateRetVoid(); else irb->CreateRet(ci); // The function should be valid now verifyFunction(*newProc); { // Inline the call DataLayout *td = new DataLayout(this->llvmMod); InlineFunctionInfo i(NULL, td); bool success = InlineFunction(ci, i); assert(success); verifyFunction(*newProc); } //newProc->dump(); return newProc; }
int main(int argc, char** argv){ // verif M unit #ifdef CORE_DBG verif_m_unit(); #endif if(argc < 2) { return 0; } Core *pCore = Core::start(); pCore->init(); COFF_parser parser(argv[1]); pCore->set_mode(BK_AT_MAIN); if(argc >= 3) { core_mode_t mode = (core_mode_t)strtoul(argv[2],NULL,10); pCore->set_mode(mode); } if(argc >= 4) { word_t thres = strtoul(argv[3],NULL,10); Profiler::set_jit_threshold_times(thres); } if(argc >= 5) { word_t thres = strtoul(argv[4],NULL,10); Profiler::set_jit_threshold_len(thres); } parser.connect(pCore); parser.set_reverse(false); parser.parse(); pCore->init(); #if 0 pCore->reg_write(0,0,2); // A0 = 2 pCore->reg_write(1,0,3); // B0 = 3 llvm::Function *func = llvm::cast<llvm::Function>(Core::get_llvm_module().getOrInsertFunction("func", Type::getInt32Ty(getGlobalContext()),(Type*)0)); llvm::BasicBlock* bb = llvm::BasicBlock::Create(getGlobalContext(),"entry",func); Core::get_llvm_builder().SetInsertPoint(bb); llvm::Constant* a_side_addr = llvm::ConstantInt::get(llvm::Type::getInt32Ty(getGlobalContext()) ,(uint64_t)pCore->get_reg_a()); llvm::Constant* b_side_addr = llvm::ConstantInt::get(llvm::Type::getInt32Ty(getGlobalContext()) ,(uint64_t)pCore->get_reg_b()); llvm::Constant* dst_addr = llvm::ConstantInt::get(llvm::Type::getInt32Ty(getGlobalContext()) ,(uint64_t)(pCore->get_reg_b()+1)); // B1 llvm::Value* a_side = llvm::ConstantExpr::getIntToPtr(a_side_addr, llvm::PointerType::getUnqual(llvm::Type::getInt32Ty(getGlobalContext()))); llvm::Value* b_side = llvm::ConstantExpr::getIntToPtr(b_side_addr, llvm::PointerType::getUnqual(llvm::Type::getInt32Ty(getGlobalContext()))); llvm::Value* b1 = llvm::ConstantExpr::getIntToPtr(dst_addr, llvm::PointerType::getUnqual(llvm::Type::getInt32Ty(getGlobalContext()))); llvm::Value* left = Core::get_llvm_builder().CreateLoad(a_side); llvm::Value* right = Core::get_llvm_builder().CreateLoad(b_side); llvm::Value* re = Core::get_llvm_builder().CreateAdd(left,right); Core::get_llvm_builder().CreateStore(re,b1,true); Core::get_llvm_builder().CreateRet(re); ExecutionEngine* EE = EngineBuilder(&Core::get_llvm_module()).create(); // Call the `foo' function with no arguments: //std::vector<GenericValue> noargs; //GenericValue gv = EE->runFunction(func, noargs); void* FPtr = EE->getPointerToFunction(func); int (*FP)() = (int (*)())(intptr_t)FPtr; FP(); // Import result of execution: std::cout << "Result: " << pCore->reg_read(B_SIDE,1) << "\n"; //outs() << "re: " << gv.IntVal << "\n"; #endif #if 0 pCore->reg_write(A_SIDE,3,0xFF); de_func_t de_func = JIT::gen_su_de_32bit_1or2_src_shl_f2_nc(pCore,0x018d0ca0); c6x::Instruction inst; pCore->reg_ch_num = 1; de_func(pCore,&inst); pCore->step(); std::cout << to_hex_str(pCore->reg_read(A_SIDE,3)) << "\n"; system("pause"); #endif pCore->run(); return 0; }
RCntxt globalContext() { return RCntxt(getGlobalContext()); }
emscripten::val ContextWebAudio::getRawContext() { return getGlobalContext(); }
CodeGenContext::CodeGenContext() { module = new Module("main", getGlobalContext()); blocks = new stack<CodeGenBlock *>(); }
void WasmScript::GenerateGeneralScriptCalls(WasmFile* file) { // Now generate this function prototype: execute_script: // Returns a integer is the result of all script. // If successful, returns -1. // It will fail otherwise and return the line number of the failure. // This method has no parameters. std::vector<llvm::Type*> params; // Then get the result: integer. llvm::Type* result_type = llvm::Type::getInt32Ty(llvm::getGlobalContext()); WasmModule* wasm_module = file->GetAssertModule(); llvm::Module* module = wasm_module->GetModule(); // Finally, create the function type. llvm::FunctionType* fct_type = llvm::FunctionType::get(result_type, params, false); const char* name = "execute_script"; llvm::Function* fct = llvm::Function::Create(fct_type, Function::ExternalLinkage, name, module); // Now create the first bb. llvm::BasicBlock* bb = llvm::BasicBlock::Create(getGlobalContext(), "entry", fct); llvm::IRBuilder<> builder(getGlobalContext()); builder.SetInsertPoint(bb); WasmFunction* wasm_fct = new WasmFunction(nullptr, name, fct, wasm_module, INT_32); const char* result_name = "result"; Variable* result = new Variable(result_name); wasm_fct->Allocate(result_name, llvm::Type::getInt32Ty(llvm::getGlobalContext()), builder); // Now generate our IR and then use our codegen for it. for (auto elem : script_elems_) { Expression* expr = nullptr; if (dynamic_cast<WasmInvoke*>(elem) != nullptr) { expr = HandleInvoke(elem); } else { CallExpression* call = HandleAssert(wasm_module, elem); // Set the value in a local. SetLocal* set = new SetLocal(result, call); // In the assert_return case, we want to compare this to -1. Const* minus_one = new Const(INT_32, new ValueHolder(-1)); Operation* op = new Operation(NE_OPER, INT_32); Binop* cmp = new Binop(op, set, minus_one); // Now we can generate the return 0; GetLocal* get = new GetLocal(result); ReturnExpression* return_expr = new ReturnExpression(get); // Finally, generate the AST for this assert. IfExpression* inst = new IfExpression(cmp, return_expr); expr = inst; } // Now we can generate it. expr->Codegen(wasm_fct, builder); delete expr, expr = nullptr; } Const* one = new Const(INT_32, new ValueHolder(-1)); ReturnExpression* return_expr = new ReturnExpression(one); return_expr->Codegen(wasm_fct, builder); delete return_expr, return_expr = nullptr; }
Value *FuncDef::compile(CodeGen &gen) const { log.debug("Compiling function '%s'", ident->getName()->c_str()); LLVMContext *context = &gen.getBuilder()->getContext(); IRBuilder<> &b = *gen.getBuilder(); // TODO map types std::vector<llvm::Type *> fn_args; for (unsigned int i = 0; i < args->size(); i++) { llvm::Type *argType = llvm::Type::getInt32Ty(*context); fn_args.push_back(argType); } FunctionType *ft = FunctionType::get(llvm::Type::getInt32Ty(*context), fn_args, false); Function *fn = Function::Create(ft, Function::ExternalLinkage, *ident->getName(), gen.getModule()); gen.registerFunction(fn); BasicBlock *bb = BasicBlock::Create(getGlobalContext(), *ident->getName(), fn); BasicBlock *last_block = gen.getBuilder()->GetInsertBlock(); gen.getBuilder()->SetInsertPoint(bb); // store each arg in memory so that it can be retreived // by the Ident node unsigned int i = 0; for (Function::arg_iterator it = fn->arg_begin(); i != args->size(); ++it, ++i) { it->setName(*args->getIdent(i).getName()); log.debug("Saving arg '%s' into memory", args->getIdent(i).getName()->c_str()); llvm::Type *mem_type = llvm::Type::getInt32Ty(*context); ConstantInt *mem_count = b.getInt32(1); AllocaInst *mem = b.CreateAlloca(mem_type, mem_count, "arg_ptr"); b.CreateStore(it, mem); // just returns a void Value gen.registerValue(*args->getIdent(i).getName(), mem); } // generate function termintaor Value *terminator = NULL; if (block != NULL) { const Node *current = block; while (current != NULL) { log.debug("Compiling node in block"); terminator = current->compile(gen); current = current->getNext(); if (current == NULL) { log.debug("Next node in block is NULL"); } } } else { terminator = ConstantInt::get(*context, APInt(32, 0, false)); } gen.getBuilder()->CreateRet(terminator); gen.getBuilder()->SetInsertPoint(last_block); return fn; }
bool LoopBarriers::ProcessLoop(Loop *L, LPPassManager &LPM) { bool isBLoop = false; bool changed = false; for (Loop::block_iterator i = L->block_begin(), e = L->block_end(); i != e && !isBLoop; ++i) { for (BasicBlock::iterator j = (*i)->begin(), e = (*i)->end(); j != e; ++j) { if (isa<BarrierInst>(j)) { isBLoop = true; break; } } } LLVMContext &LC = getGlobalContext(); IntegerType * IntTy = IntegerType::get(LC, 32); Value *Args = ConstantInt::get(IntTy, 0); for (Loop::block_iterator i = L->block_begin(), e = L->block_end(); i != e && isBLoop; ++i) { for (BasicBlock::iterator j = (*i)->begin(), e = (*i)->end(); j != e; ++j) { if (isa<BarrierInst>(j)) { BasicBlock *preheader = L->getLoopPreheader(); assert((preheader != NULL) && "Non-canonicalized loop found!\n"); Instruction *PhdrBarrierInst = BarrierInst::createBarrier(Args, preheader->getTerminator()); MDNode* PhdrAuxBarrierInfo = MDNode::get(LC, MDString::get(LC, "auxiliary phdr barrier")); PhdrBarrierInst->setMetadata("aux.phdr.barrier", PhdrAuxBarrierInfo); preheader->setName(preheader->getName() + ".loopbarrier"); BasicBlock *header = L->getHeader(); if (header->getFirstNonPHI() != &header->front()) { Instruction *HdrBarrierInst = BarrierInst::createBarrier(Args, header->getFirstNonPHI()); MDNode* HdrAuxBarrierInfo = MDNode::get(LC, MDString::get(LC, "auxiliary phihdr barrier")); HdrBarrierInst->setMetadata("aux.phihdr.barrier", HdrAuxBarrierInfo); header->setName(header->getName() + ".phibarrier"); } /* SmallVector<BasicBlock*, 8> ExitingBlocks; L->getExitingBlocks(ExitingBlocks); */ BasicBlock *brexit = L->getExitingBlock(); if (brexit != NULL) { Instruction *ExitingBarrierInst = BarrierInst::createBarrier(Args, brexit->getTerminator()); MDNode* ExitingAuxBarrierInfo = MDNode::get(LC, MDString::get(LC, "auxiliary exiting barrier")); ExitingBarrierInst->setMetadata("aux.exiting.barrier", ExitingAuxBarrierInfo); brexit->setName(brexit->getName() + ".brexitbarrier"); } BasicBlock *latch = L->getLoopLatch(); if (latch != NULL && brexit != latch) { Instruction *LatchBarrierInst = BarrierInst::createBarrier(Args, latch->getTerminator()); MDNode* LatchAuxBarrierInfo = MDNode::get(LC, MDString::get(LC, "auxiliary latch barrier")); LatchBarrierInst->setMetadata("aux.latch.barrier", LatchAuxBarrierInfo); latch->setName(latch->getName() + ".latchbarrier"); return changed; } BasicBlock *Header = L->getHeader(); typedef GraphTraits<Inverse<BasicBlock *> > InvBlockTraits; InvBlockTraits::ChildIteratorType PI = InvBlockTraits::child_begin(Header); InvBlockTraits::ChildIteratorType PE = InvBlockTraits::child_end(Header); BasicBlock *Latch = NULL; for (; PI != PE; ++PI) { InvBlockTraits::NodeType *N = *PI; if (L->contains(N)) { Latch = N; if (DT->dominates(j->getParent(), Latch)) { BarrierInst::createBarrier(Args, Latch->getTerminator()); Latch->setName(Latch->getName() + ".latchbarrier"); } } } return true; } } } BasicBlock *preheader = L->getLoopPreheader(); assert((preheader != NULL) && "Non-canonicalized loop found!\n"); TerminatorInst *t = preheader->getTerminator(); Instruction *prev = NULL; if (&preheader->front() != t) { // If t is not the first/only instruction in the block, get the previous // instruction. prev = t->getPrevNode(); } if (prev && isa<BarrierInst>(prev)) { BasicBlock *new_b = SplitBlock(preheader, t, this); new_b->setName(preheader->getName() + ".postbarrier_dummy"); return true; } return changed; }
namespace nqp { static IRBuilder<> Builder(getGlobalContext()); static const PointerType *GenericPointerType = Type::getInt8PtrTy(getGlobalContext(), 0); CodeGenContext::CodeGenContext(LLVMContext &context) : context(context) { module = new Module(StringRef("main"), context); vector<const Type*> Args = vector<const Type*>(1, Type::getInt64Ty(getGlobalContext())); FunctionType *FT = FunctionType::get(GenericPointerType, Args, false); Function::Create(FT, Function::ExternalLinkage, "construct_int", module); Args = vector<const Type*>(1, Type::getDoubleTy(getGlobalContext())); FT = FunctionType::get(GenericPointerType, Args, false); Function::Create(FT, Function::ExternalLinkage, "construct_num", module); FT = FunctionType::get(GenericPointerType, false); Function::Create(FT, Function::ExternalLinkage, "construct_array", module); Args = vector<const Type*>(); Args.push_back(GenericPointerType); Args.push_back(GenericPointerType); FT = FunctionType::get(Type::getVoidTy(getGlobalContext()), Args, false); Function::Create(FT, Function::ExternalLinkage, "array_push", module); Args = vector<const Type*>(); Args.push_back(Type::getInt8PtrTy(getGlobalContext())); Args.push_back(Type::getInt64Ty(getGlobalContext())); FT = FunctionType::get(GenericPointerType, Args, false); Function::Create(FT, Function::ExternalLinkage, "construct_str", module); Args = vector<const Type*>(); Args.push_back(Type::getInt8PtrTy(getGlobalContext())); Args.push_back(Type::getInt64Ty(getGlobalContext())); FT = FunctionType::get(GenericPointerType, Args, false); Function::Create(FT, Function::ExternalLinkage, "construct_str", module); FT = FunctionType::get(GenericPointerType, true); Function::Create(FT, Function::ExternalLinkage, "vm_dispatch", module); } /* Compile the AST into a module */ void CodeGenContext::generateCode(Block& root) { std::cout << "Generating code...\n"; std::cout << "Nodes: " << root.statements.size() << "\n"; /* Create the top level interpreter function to call as entry */ vector<const Type*> argTypes; FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()), argTypes, false); mainFunction = Function::Create(ftype, GlobalValue::InternalLinkage, "main", module); BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), "entry", mainFunction, 0); /* Push a new variable/block context */ pushBlock(bblock); root.codeGen(*this); /* emit bytecode for the toplevel block */ ReturnInst::Create(getGlobalContext(), bblock); popBlock(); /* Print the bytecode in a human-readable format to see if our program compiled properly */ std::cout << "Code is generated.\n"; PassManager pm; pm.add(createPrintModulePass(&outs())); pm.run(*module); } /* Executes the AST by running the main function */ GenericValue CodeGenContext::runCode() { std::cout << "Running code...\n"; //ExistingModuleProvider *mp = new ExistingModuleProvider(module); ExecutionEngine *ee = ExecutionEngine::create(module, false); vector<GenericValue> noargs; GenericValue v = ee->runFunction(mainFunction, noargs); std::cout << "Code was run.\n"; return v; } /* Returns an LLVM type based on the identifier */ static const Type *typeOf(const Identifier& type) { cout << "typeOf.? " << endl; if (type.name.compare("int") == 0) { return Type::getInt64Ty(getGlobalContext()); } else if (type.name.compare("double") == 0) { return Type::getDoubleTy(getGlobalContext()); } return Type::getVoidTy(getGlobalContext()); } /* -- Code Generation -- */ Value* IntegerConstant::codeGen(CodeGenContext& context) { std::cout << "Creating integer: " << value << endl; Function *construct_int = context.module->getFunction("construct_int"); if (construct_int == NULL) { std::cerr << "Bad construct int" << endl; } std::vector<Value*> ArgsV; ArgsV.push_back(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), value, true)); return CallInst::Create(construct_int, ArgsV.begin(), ArgsV.end(), "", context.currentBlock()); } Value* DoubleConstant::codeGen(CodeGenContext& context) { std::cout << "Creating double: " << value << endl; Function *construct_num = context.module->getFunction("construct_num"); if (construct_num == NULL) { std::cerr << "Bad construct int" << endl; } std::vector<Value*> ArgsV; ArgsV.push_back(ConstantFP::get(Type::getDoubleTy(getGlobalContext()), value)); return CallInst::Create(construct_num, ArgsV.begin(), ArgsV.end(), "", context.currentBlock()); } Value* StringConstant::codeGen(CodeGenContext& context) { std::cout << "Construing String: " << value << endl; Function *construct_str = context.module->getFunction("construct_str"); if (construct_str == NULL) { std::cerr << "Bad construct int" << endl; } cout << "Value is: " << value << endl; GlobalVariable *val; StringMap<GlobalVariable*>::iterator iter = context.globals.find(value); if (iter == context.globals.end()) { const ArrayType *str_type = ArrayType::get(Type::getInt8Ty(getGlobalContext()), value.length() + 1); std::vector<Constant *> ary_elements; for (unsigned int i = 1; i < value.length() - 1; i++) { ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), value[i])); } ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), 0)); val = new GlobalVariable(*context.module, str_type, true, GlobalValue::InternalLinkage, ConstantArray::get(str_type, ary_elements), ""); context.globals[value] = val; } else { val = iter->second; } std::vector<Value*> ArgsV; ArgsV.push_back(val); ArgsV.push_back(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), value.length() - 2)); return CallInst::Create(construct_str, ArgsV.begin(), ArgsV.end(), "", context.currentBlock()); } Value* Identifier::codeGen(CodeGenContext& context) { std::cout << "Creating identifier reference: " << name << endl; if (context.locals().find(name) == context.locals().end()) { std::cerr << "undeclared variable " << name << endl; return NULL; } return new LoadInst(context.locals()[name], "", false, context.currentBlock()); } Value* BlockReturn::codeGen(CodeGenContext& context) { std::cout << "Creating return instruciton" << endl; ReturnInst *ret = ReturnInst::Create(getGlobalContext(), expression.codeGen(context)); return ret; } Value* MethodCall::codeGen(CodeGenContext& context) { GlobalVariable *val; StringMap<GlobalVariable*>::iterator iter = context.globals.find(id.name); if (iter == context.globals.end()) { const ArrayType *str_type = ArrayType::get(Type::getInt8Ty(getGlobalContext()), id.name.length() + 1); std::vector<Constant *> ary_elements; for (unsigned int i = 0; i < id.name.length(); i++) { ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), id.name[i])); } ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), 0)); val = new GlobalVariable(*context.module, str_type, true, GlobalValue::InternalLinkage, ConstantArray::get(str_type, ary_elements), ""); context.globals[id.name] = val; } else { val = iter->second; } Function *function = context.module->getFunction("vm_dispatch"); std::vector<Value*> args; ExpressionList::const_iterator it; args.push_back(val); args.push_back(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), arguments->size(), true)); for (it = arguments->begin(); it != arguments->end(); it++) { args.push_back((*it)->codeGen(context)); } CallInst *call = CallInst::Create(function, args.begin(), args.end(), "", context.currentBlock()); std::cout << "Creating method call: " << id.name << endl; return call; } Value* PrefixOp::codeGen(CodeGenContext& context) { string name; switch (op) { case token::T_PLUS: // Call prefix:<+> name = "&prefix:<+>"; break; case token::T_BAR: // Call infix:<|> name = "&prefix:<|>"; break; case token::T_STITCH: // Call prefix:<~> name = "&prefix:<~>"; break; default: { /* not implemented */ return NULL; } } Function *function = context.module->getFunction("vm_dispatch"); const ArrayType *str_type = ArrayType::get(Type::getInt8Ty(getGlobalContext()), name.length() + 1); std::vector<Constant *> ary_elements; for (unsigned int i = 0; i < name.length(); i++) { ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), name[i])); } ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), 0)); GlobalVariable *method_name = new GlobalVariable(*context.module, str_type, true, GlobalValue::InternalLinkage, ConstantArray::get(str_type, ary_elements), ""); std::vector<Value*> args; args.push_back(method_name); args.push_back(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), 1, true)); args.push_back(val.codeGen(context)); return CallInst::Create(function, args.begin(), args.end(), "", context.currentBlock()); } Value* BinaryOp::codeGen(CodeGenContext& context) { std::cout << "Creating infix operation " << op << endl; string name; switch (op) { case token::T_PLUS: // Call infix:<+> name = "&infix:<+>"; break; case token::T_MINUS: // Call infix:<-> name = "&infix:<->"; break; case token::T_MUL: // Call infix:<*> name = "&infix:<*>"; break; case token::T_DIV: // Call infix:</> name = "&infix:</>"; break; case token::T_STITCH: // Call infix:<~> name = "&infix:<~>"; break; /* TODO comparison */ default: { /* not implemented */ return NULL; } } Function *function = context.module->getFunction("vm_dispatch"); const ArrayType *str_type = ArrayType::get(Type::getInt8Ty(getGlobalContext()), name.length() + 1); std::vector<Constant *> ary_elements; for (unsigned int i = 0; i < name.length(); i++) { ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), name[i])); } ary_elements.push_back(ConstantInt::get(Type::getInt8Ty(getGlobalContext()), 0)); GlobalVariable *val = new GlobalVariable(*context.module, str_type, true, GlobalValue::InternalLinkage, ConstantArray::get(str_type, ary_elements), ""); std::vector<Value*> args; args.push_back(val); args.push_back(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), 2, true)); args.push_back(lhs.codeGen(context)); args.push_back(rhs.codeGen(context)); return CallInst::Create(function, args.begin(), args.end(), "", context.currentBlock()); } Value* Assignment::codeGen(CodeGenContext& context) { if (context.locals().find(lhs.name) == context.locals().end()) { std::cerr << "undeclared variable " << lhs.name << endl; return NULL; } return new StoreInst(rhs.codeGen(context), context.locals()[lhs.name], false, context.currentBlock()); } Value* Block::codeGen(CodeGenContext& context) { StatementList::const_iterator it; Value *last = NULL; // create unsigned int count = 0; for (it = statements.begin(); it != statements.end(); it++) { std::cout << "Generating code for " << typeid(**it).name() << endl; last = (**it).codeGen(context); count++; std::cout << "Generatoring code for " << count << endl; } std::cout << "Creating block" << endl; return last; } Value* ExpressionStatement::codeGen(CodeGenContext& context) { std::cout << "Generating code for " << typeid(expression).name() << endl; return expression.codeGen(context); } Value* VariableDeclaration::codeGen(CodeGenContext& context) { std::cout << "Creating variable declaration " << id.name << endl; AllocaInst *alloc = new AllocaInst(GenericPointerType, id.name.c_str(), context.currentBlock()); context.locals()[id.name] = alloc; if (assignmentExpr != NULL) { Assignment assn(id, assignment, *assignmentExpr); assn.codeGen(context); } return alloc; } Value* ListDeclaration::codeGen(CodeGenContext& context) { std::cout << "Constructing new Array of length: " << list_values->size() << endl; Function *function = context.module->getFunction("construct_array"); Value* new_array = CallInst::Create(function, "", context.currentBlock()); for (ExpressionList::iterator it = list_values->begin(); it != list_values->end(); ++it) { function = context.module->getFunction("array_push"); std::vector<Value*> args; args.push_back(new_array); args.push_back((*it)->codeGen(context)); CallInst::Create(function, args.begin(), args.end(), "", context.currentBlock()); } return new_array; } Value* ParameterDeclaration::codeGen(CodeGenContext& context) { AllocaInst *alloc; return alloc; } Value* FunctionDeclaration::codeGen(CodeGenContext& context) { vector<const Type*> argTypes; ParameterList::const_iterator it; for (it = arguments.begin(); it != arguments.end(); it++) { //argTypes.push_back(typeOf((**it).type)); } FunctionType *ftype = FunctionType::get(Type::getInt64Ty(getGlobalContext()), argTypes, false); Function *function = Function::Create(ftype, GlobalValue::InternalLinkage, id.name.c_str(), context.module); BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), "entry", function, 0); context.pushBlock(bblock); for (it = arguments.begin(); it != arguments.end(); it++) { (**it).codeGen(context); } block.codeGen(context); ReturnInst::Create(getGlobalContext(), bblock); context.popBlock(); std::cout << "Creating function: " << id.name << endl; return function; } Value* IfBlock::codeGen(CodeGenContext& context) { return NULL; } } /* end namespace nqp */