bool CLIPSFunctionPass::runOnFunction(llvm::Function& function) { if(!function.isDeclaration()) { void* env = getEnvironment(); CLIPSEnvironment* clEnv = new CLIPSEnvironment(env); EnvReset(env); CLIPSPassHeader* header = (CLIPSPassHeader*)getIndirectPassHeader(); char* passes = CharBuffer(strlen(header->getPasses()) + 64); sprintf(passes,"(passes %s)", header->getPasses()); EnvAssertString(env, passes); free(passes); KnowledgeConstructor tmp; if(header->needsLoops() && header->needsRegions()) { llvm::LoopInfo& li = getAnalysis<LoopInfo>(); llvm::RegionInfo& ri = getAnalysis<RegionInfo>(); tmp.route(function, li, ri); } else if(header->needsLoops() && !header->needsRegions()) { llvm::LoopInfo& li = getAnalysis<LoopInfo>(); tmp.route(function, li); } else if(header->needsRegions() && !header->needsLoops()) { llvm::RegionInfo& ri = getAnalysis<RegionInfo>(); tmp.route(function, ri); } else { tmp.route(function); } clEnv->makeInstances((char*)tmp.getInstancesAsString().c_str()); //TODO: put in the line to build the actual knowledge EnvRun(env, -1L); //it's up to the code in the expert system to make changes EnvReset(env); return true; } else { return false; } }
void createPrimitiveDestructor(Module& module, const SEM::TypeInstance* const typeInstance, llvm::Function& llvmFunction) { assert(llvmFunction.isDeclaration()); Function functionGenerator(module, llvmFunction, destructorArgInfo(module, *typeInstance), &(module.templateBuilder(TemplatedObject::TypeInstance(typeInstance)))); const auto debugInfo = genDebugDestructorFunction(module, *typeInstance, &llvmFunction); functionGenerator.attachDebugInfo(debugInfo); functionGenerator.setDebugPosition(getDebugDestructorPosition(module, *typeInstance)); genPrimitiveDestructorCall(functionGenerator, typeInstance->selfType(), functionGenerator.getRawContextValue()); functionGenerator.getBuilder().CreateRetVoid(); functionGenerator.verify(); }
Function::Function(Module& pModule, llvm::Function& function, const ArgInfo& argInfo, TemplateBuilder* pTemplateBuilder) : module_(pModule), function_(function), entryBuilder_(pModule.getLLVMContext()), builder_(pModule.getLLVMContext()), createdEntryBlock_(false), useEntryBuilder_(false), argInfo_(argInfo), templateBuilder_(pTemplateBuilder), #if LOCIC_LLVM_VERSION < 307 debugInfo_(nullptr), #endif exceptionInfo_(nullptr), returnValuePtr_(nullptr), templateArgs_(nullptr), unwindState_(nullptr) { assert(function.isDeclaration()); assert(argInfo_.numArguments() == function_.getFunctionType()->getNumParams()); // Add a bottom level unwind stack. unwindStackStack_.push(UnwindStack()); // Add bottom level action for this function. unwindStack().push_back(UnwindAction::FunctionMarker()); const auto startBB = createBasicBlock(""); builder_.SetInsertPoint(startBB); argValues_.reserve(function_.arg_size()); for (auto arg = function_.arg_begin(); arg != function_.arg_end(); ++arg) { argValues_.push_back(arg); } std::vector<llvm_abi::Type*> argABITypes; argABITypes.reserve(argInfo.argumentTypes().size()); std::vector<llvm::Type*> argLLVMTypes; argLLVMTypes.reserve(argInfo.argumentTypes().size()); for (const auto& typePair : argInfo.argumentTypes()) { argABITypes.push_back(typePair.first); argLLVMTypes.push_back(typePair.second); } SetUseEntryBuilder useEntryBuilder(*this); // Decode arguments according to ABI. decodeABIValues(argValues_, argABITypes, argLLVMTypes); }
bool _runOnFunction(llvm::Function& f) { Timer _t2("(sum)"); Timer _t("initializing"); initialize(); _t.split("overhead"); // f.dump(); llvm::Module* cur_module = f.getParent(); #if LLVMREV < 217548 llvm::PassManager fake_pm; #else llvm::legacy::PassManager fake_pm; #endif llvm::InlineCostAnalysis* cost_analysis = new llvm::InlineCostAnalysis(); fake_pm.add(cost_analysis); // llvm::errs() << "doing fake run\n"; fake_pm.run(*fake_module); // llvm::errs() << "done with fake run\n"; bool did_any_inlining = false; // TODO I haven't gotten the callgraph-updating part of the inliner to work, // so it's not easy to tell what callsites have been inlined into (ie added to) // the function. // One simple-but-not-great way to handle it is to just iterate over the entire function // multiple times and re-inline things until we don't want to inline any more; // NPASSES controls the maximum number of times to attempt that. // Right now we actually don't need that, since we only inline fully-optimized // functions (from the stdlib), and those will already have had inlining // applied recursively. const int NPASSES = 1; for (int passnum = 0; passnum < NPASSES; passnum++) { _t.split("collecting calls"); std::vector<llvm::CallSite> calls; for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) { llvm::CallInst* call = llvm::dyn_cast<llvm::CallInst>(&(*I)); // From Inliner.cpp: if (!call || llvm::isa<llvm::IntrinsicInst>(call)) continue; // I->dump(); llvm::CallSite CS(call); llvm::Value* v = CS.getCalledValue(); llvm::ConstantExpr* ce = llvm::dyn_cast<llvm::ConstantExpr>(v); if (!ce) continue; assert(ce->isCast()); llvm::ConstantInt* l_addr = llvm::cast<llvm::ConstantInt>(ce->getOperand(0)); int64_t addr = l_addr->getSExtValue(); if (addr == (int64_t)printf) continue; llvm::Function* f = g.func_addr_registry.getLLVMFuncAtAddress((void*)addr); if (f == NULL) { if (VERBOSITY()) { printf("Giving up on inlining %s:\n", g.func_addr_registry.getFuncNameAtAddress((void*)addr, true).c_str()); call->dump(); } continue; } // We load the bitcode lazily, so check if we haven't yet fully loaded the function: if (f->isMaterializable()) { #if LLVMREV < 220600 f->Materialize(); #else f->materialize(); #endif } // It could still be a declaration, though I think the code won't generate this case any more: if (f->isDeclaration()) continue; // Keep this section as a release_assert since the code-to-be-inlined, as well as the inlining // decisions, can be different in release mode: int op_idx = -1; for (llvm::Argument& arg : f->args()) { ++op_idx; llvm::Type* op_type = call->getOperand(op_idx)->getType(); if (arg.getType() != op_type) { llvm::errs() << f->getName() << " has arg " << op_idx << " mismatched!\n"; llvm::errs() << "Given "; op_type->dump(); llvm::errs() << " but underlying function expected "; arg.getType()->dump(); llvm::errs() << '\n'; } RELEASE_ASSERT(arg.getType() == call->getOperand(op_idx)->getType(), ""); } assert(!f->isDeclaration()); CS.setCalledFunction(f); calls.push_back(CS); } // assert(0 && "TODO"); // printf("%ld\n", calls.size()); bool did_inline = false; _t.split("doing inlining"); while (calls.size()) { llvm::CallSite cs = calls.back(); calls.pop_back(); // if (VERBOSITY("irgen.inlining") >= 1) { // llvm::errs() << "Evaluating callsite "; // cs->dump(); //} llvm::InlineCost IC = cost_analysis->getInlineCost(cs, threshold); bool do_inline = false; if (IC.isAlways()) { if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "always inline\n"; do_inline = true; } else if (IC.isNever()) { if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "never inline\n"; do_inline = false; } else { if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "Inline cost: " << IC.getCost() << '\n'; do_inline = (bool)IC; } if (VERBOSITY("irgen.inlining") >= 1) { if (!do_inline) llvm::outs() << "not "; llvm::outs() << "inlining "; cs->dump(); } if (do_inline) { static StatCounter num_inlines("num_inlines"); num_inlines.log(); // llvm::CallGraph cg(*f.getParent()); ////cg.addToCallGraph(cs->getCalledFunction()); // llvm::InlineFunctionInfo InlineInfo(&cg); llvm::InlineFunctionInfo InlineInfo; bool inlined = llvm::InlineFunction(cs, InlineInfo, false); did_inline = did_inline || inlined; did_any_inlining = did_any_inlining || inlined; // if (inlined) // f.dump(); } } if (!did_inline) { if (passnum >= NPASSES - 1 && VERBOSITY("irgen.inlining")) printf("quitting after %d passes\n", passnum + 1); break; } } // TODO would be nice to break out here and not have to rematerialize the function; // I think I have to do that even if no inlining happened from the "setCalledFunction" call above. // I thought that'd just change the CS object, but maybe it changes the underlying instruction as well? // if (!did_any_inlining) // return false; _t.split("remapping"); llvm::ValueToValueMapTy VMap; for (llvm::Function::iterator I = f.begin(), E = f.end(); I != E; ++I) { VMap[I] = I; } MyMaterializer materializer(cur_module); for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) { RemapInstruction(&(*I), VMap, llvm::RF_None, NULL, &materializer); } _t.split("cleaning up"); std::vector<llvm::GlobalValue*> to_remove; for (llvm::Module::global_iterator I = cur_module->global_begin(), E = cur_module->global_end(); I != E; ++I) { if (I->use_empty()) { to_remove.push_back(I); continue; } } for (int i = 0; i < to_remove.size(); i++) { to_remove[i]->eraseFromParent(); } for (llvm::Module::iterator I = cur_module->begin(), E = cur_module->end(); I != E;) { if (!I->isDeclaration()) { ++I; continue; } if (I->use_empty()) { I = cur_module->getFunctionList().erase(I); } else { ++I; } } return did_any_inlining; }