bool handleBool(LoadInst *li, GlobalVariable *gv) { if (VERBOSITY()) { llvm::errs() << "Constant-folding this load: " << *li << '\n'; } if (gv->getName() == "True") li->replaceAllUsesWith(embedConstantPtr(True, g.llvm_bool_type_ptr)); else li->replaceAllUsesWith(embedConstantPtr(False, g.llvm_bool_type_ptr)); return true; }
void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*>& arg_types) { assert(arg_types.size() == cl_f->numReceivedArgs()); #ifndef NDEBUG for (ConcreteCompilerType* t : arg_types) assert(t); #endif FunctionSpecialization* spec = new FunctionSpecialization(processType(rtn_type), arg_types); std::vector<llvm::Type*> llvm_arg_types; int npassed_args = arg_types.size(); assert(npassed_args == cl_f->numReceivedArgs()); for (int i = 0; i < npassed_args; i++) { if (i == 3) { llvm_arg_types.push_back(g.i8_ptr->getPointerTo()); break; } llvm_arg_types.push_back(arg_types[i]->llvmType()); } llvm::FunctionType* ft = llvm::FunctionType::get(g.llvm_value_type_ptr, llvm_arg_types, false); cl_f->addVersion(new CompiledFunction(NULL, spec, false, f, embedConstantPtr(f, ft->getPointerTo()), EffortLevel::MAXIMAL, NULL)); }
void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*>& arg_types, bool takes_varargs, bool takes_kwargs) { FunctionSignature* sig = new FunctionSignature(processType(rtn_type), NULL, 0, takes_varargs, takes_kwargs); for (int i = 0; i < arg_types.size(); i++) { sig->arg_types.push_back(processType(arg_types[i])); } std::vector<llvm::Type*> llvm_arg_types; int npassed_args = arg_types.size(); if (takes_varargs) npassed_args++; if (takes_kwargs) npassed_args++; for (int i = 0; i < npassed_args; i++) { if (i == 3) { llvm_arg_types.push_back(g.llvm_value_type_ptr->getPointerTo()); break; } llvm_arg_types.push_back(g.llvm_value_type_ptr); } llvm::FunctionType* ft = llvm::FunctionType::get(g.llvm_value_type_ptr, llvm_arg_types, false); cl_f->addVersion( new CompiledFunction(NULL, sig, false, f, embedConstantPtr(f, ft->getPointerTo()), EffortLevel::MAXIMAL, NULL)); }
void addRTFunction(CLFunction *cl_f, void* f, ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*> &arg_types, bool is_vararg) { FunctionSignature *sig = new FunctionSignature(processType(rtn_type), is_vararg); std::vector<llvm::Type*> llvm_arg_types; for (int i = 0; i < arg_types.size(); i++) { sig->arg_types.push_back(processType(arg_types[i])); llvm_arg_types.push_back(g.llvm_value_type_ptr); } llvm::FunctionType *ft = llvm::FunctionType::get(g.llvm_value_type_ptr, llvm_arg_types, false); cl_f->addVersion(new CompiledFunction(NULL, sig, false, f, embedConstantPtr(f, ft->getPointerTo()), EffortLevel::MAXIMAL, NULL)); }
// Returns a llvm::Constant char* to a global string constant llvm::Constant* getStringConstantPtr(const std::string& str) { const char* c; if (strings.count(str)) { c = strings[str]; } else { char* buf = (char*)malloc(str.size() + 1); memcpy(buf, str.c_str(), str.size()); buf[str.size()] = '\0'; strings[str] = buf; c = buf; } return embedConstantPtr(c, g.i8->getPointerTo()); }
static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) { assert(cf); assert(cf->func); // g.engine->finalizeOBject(); if (VERBOSITY("irgen") >= 1) { printf("Compiling...\n"); // g.cur_module->dump(); } void* compiled = NULL; if (effort > EffortLevel::INTERPRETED) { Timer _t("to jit the IR"); #if LLVMREV < 215967 g.engine->addModule(cf->func->getParent()); #else g.engine->addModule(std::unique_ptr<llvm::Module>(cf->func->getParent())); #endif compiled = (void*)g.engine->getFunctionAddress(cf->func->getName()); assert(compiled); cf->llvm_code = embedConstantPtr(compiled, cf->func->getType()); long us = _t.end(); static StatCounter us_jitting("us_compiling_jitting"); us_jitting.log(us); static StatCounter num_jits("num_jits"); num_jits.log(); } else { // HAX just get it for now; this is just to make sure everything works //(void*)g.func_registry.getFunctionAddress(cf->func->getName()); } cf->code = compiled; if (VERBOSITY("irgen") >= 1) { printf("Compiled function to %p\n", compiled); } StackMap* stackmap = parseStackMap(); patchpoints::processStackmap(stackmap); }
llvm::Constant* embedRelocatablePtr(const void* addr, llvm::Type* type, llvm::StringRef shared_name) { assert(addr); if (!ENABLE_JIT_OBJECT_CACHE) return embedConstantPtr(addr, type); std::string name; if (!shared_name.empty()) { llvm::GlobalVariable* gv = g.cur_module->getGlobalVariable(shared_name, true); if (gv) return gv; assert(!relocatable_syms.count(name)); name = shared_name; } else { name = (llvm::Twine("c") + llvm::Twine(relocatable_syms.size())).str(); } relocatable_syms[name] = addr; llvm::Type* var_type = type->getPointerElementType(); return new llvm::GlobalVariable(*g.cur_module, var_type, true, llvm::GlobalVariable::ExternalLinkage, 0, name); }
void replaceUsesWithConstant(llvm::Value* v, uintptr_t val) { if (isa<PointerType>(v->getType())) v->replaceAllUsesWith(embedConstantPtr((void*)val, v->getType())); else v->replaceAllUsesWith(getConstantInt(val, v->getType())); }
bool handleCls(LoadInst *li, GlobalVariable *gv) { bool changed = true; if (VERBOSITY("opt") >= 1) { errs() << "\nFound load of class-typed global variable:\n" << *li << '\n'; } BoxedClass *cls = getClassFromGV(gv); if (!cls->is_constant) { assert(0 && "what globally-resolved classes are not constant??"); if (VERBOSITY("opt") >= 1) { errs() << gv->getName() << " is not constant; moving on\n"; } return false; } std::vector<Instruction*> to_remove; for (User* user : li->users()) { if (CallInst *call = dyn_cast<CallInst>(user)) { if (call->getCalledFunction()->getName() == "_maybeDecrefCls") { errs() << "Found decrefcls call: " << *call << '\n'; if (!isUserDefined(cls)) { // Don't delete right away; I think that invalidates the iterator // we're currently iterating over to_remove.push_back(call); } } continue; } GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(user); if (!gep) { //errs() << "Not a gep: " << *user << '\n'; continue; } APInt ap_offset(64, 0, true); bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); assert(success); int64_t offset = ap_offset.getSExtValue(); errs() << "Found a gep at offset " << offset << ": " << *gep << '\n'; for (User* gep_user : gep->users()) { LoadInst *gep_load = dyn_cast<LoadInst>(gep_user); if (!gep_load) { //errs() << "Not a load: " << *gep_user << '\n'; continue; } errs() << "Found a load: " << *gep_load << '\n'; if (offset == CLS_DTOR_OFFSET) { errs() << "Dtor; replacing with " << cls->dtor << "\n"; replaceUsesWithConstant(gep_load, (uintptr_t)cls->dtor); changed = true; } else if (offset == CLS_HASATTRS_OFFSET) { errs() << "Hasattrs; replacing with " << cls->hasattrs << "\n"; replaceUsesWithConstant(gep_load, cls->hasattrs); changed = true; } } } for (int i = 0; i < to_remove.size(); i++) { to_remove[i]->eraseFromParent(); changed = true; } if (VERBOSITY()) { llvm::errs() << "Constant-folding this load: " << *li << '\n'; } li->replaceAllUsesWith(embedConstantPtr(cls, g.llvm_class_type_ptr)); changed = true; return changed; }
bool handleCls(LoadInst* li, GlobalVariable* gv) { bool changed = true; if (VERBOSITY("opt") >= 1) { errs() << "\nFound load of class-typed global variable:\n" << *li << '\n'; } BoxedClass* cls = getClassFromGV(gv); if (!cls->is_constant) { assert(0 && "what globally-resolved classes are not constant??"); if (VERBOSITY("opt") >= 1) { errs() << gv->getName() << " is not constant; moving on\n"; } return false; } std::vector<Instruction*> to_remove; for (User* user : li->users()) { if (CallInst* call = dyn_cast<CallInst>(user)) { continue; } GetElementPtrInst* gep = dyn_cast<GetElementPtrInst>(user); if (!gep) { // errs() << "Not a gep: " << *user << '\n'; continue; } APInt ap_offset(64, 0, true); #if LLVMREV < 214781 bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); #elif LLVMREV < 227113 bool success = gep->accumulateConstantOffset(*g.tm->getSubtargetImpl()->getDataLayout(), ap_offset); #else bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); #endif assert(success); int64_t offset = ap_offset.getSExtValue(); if (VERBOSITY("opt") >= 1) errs() << "Found a gep at offset " << offset << ": " << *gep << '\n'; for (User* gep_user : gep->users()) { LoadInst* gep_load = dyn_cast<LoadInst>(gep_user); if (!gep_load) { // errs() << "Not a load: " << *gep_user << '\n'; continue; } if (VERBOSITY("opt") >= 1) errs() << "Found a load: " << *gep_load << '\n'; if (offset == offsetof(BoxedClass, attrs_offset)) { if (VERBOSITY("opt") >= 1) errs() << "attrs_offset; replacing with " << cls->attrs_offset << "\n"; replaceUsesWithConstant(gep_load, cls->attrs_offset); changed = true; } else if (offset == offsetof(BoxedClass, tp_basicsize)) { if (VERBOSITY("opt") >= 1) errs() << "tp_basicsize; replacing with " << cls->tp_basicsize << "\n"; replaceUsesWithConstant(gep_load, cls->tp_basicsize); changed = true; } } } for (int i = 0; i < to_remove.size(); i++) { to_remove[i]->eraseFromParent(); changed = true; } if (VERBOSITY()) { llvm::errs() << "Constant-folding this load: " << *li << '\n'; } li->replaceAllUsesWith(embedConstantPtr(cls, g.llvm_class_type_ptr)); changed = true; return changed; }
static llvm::Value* addFunc(void* func, llvm::Type* rtn_type, llvm::ArrayRef<llvm::Type*> arg_types, bool varargs = false) { llvm::FunctionType* ft = llvm::FunctionType::get(rtn_type, arg_types, varargs); return embedConstantPtr(func, ft->getPointerTo()); }
static llvm::Value* getFunc(void* func, const char* name) { llvm::Function* f = lookupFunction(name); ASSERT(f, "%s", name); g.func_addr_registry.registerFunction(name, func, 0, f); return embedConstantPtr(func, f->getType()); }