[llvm] r226308 - [Kaleidoscope] Fix a bug in Chapter 4 of the Kaleidoscope tutorial where repeat
David Blaikie
dblaikie at gmail.com
Fri Jan 16 11:54:44 PST 2015
On Fri, Jan 16, 2015 at 11:44 AM, Lang Hames <lhames at gmail.com> wrote:
> Author: lhames
> Date: Fri Jan 16 13:44:46 2015
> New Revision: 226308
>
> URL: http://llvm.org/viewvc/llvm-project?rev=226308&view=rev
> Log:
> [Kaleidoscope] Fix a bug in Chapter 4 of the Kaleidoscope tutorial where
> repeat
> calls to functions weren't evaluated correctly.
>
> Patch by Charlie Turner. Thanks Charlie!
>
>
> Modified:
> llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp
>
> Modified: llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp?rev=226308&r1=226307&r2=226308&view=diff
>
> ==============================================================================
> --- llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp (original)
> +++ llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp Fri Jan 16 13:44:46
> 2015
> @@ -381,13 +381,253 @@ static PrototypeAST *ParseExtern() {
> }
>
>
> //===----------------------------------------------------------------------===//
> +// Quick and dirty hack
>
> +//===----------------------------------------------------------------------===//
>
Seems like a fair bit of code to introduce to a relatively small program as
a workaround/hack. But I haven't looked at it closely/understood the entire
justification, etc.
I assume this needs to be ported into all the chapters beyond 4, too?
> +
> +// FIXME: Obviously we can do better than this
> +std::string GenerateUniqueName(const char *root)
> +{
> + static int i = 0;
> + char s[16];
> + sprintf(s, "%s%d", root, i++);
> + std::string S = s;
> + return S;
> +}
> +
> +std::string MakeLegalFunctionName(std::string Name)
> +{
> + std::string NewName;
> + if (!Name.length())
> + return GenerateUniqueName("anon_func_");
> +
> + // Start with what we have
> + NewName = Name;
> +
> + // Look for a numberic first character
> + if (NewName.find_first_of("0123456789") == 0) {
> + NewName.insert(0, 1, 'n');
> + }
> +
> + // Replace illegal characters with their ASCII equivalent
> + std::string legal_elements =
> "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
> + size_t pos;
> + while ((pos = NewName.find_first_not_of(legal_elements)) !=
> std::string::npos) {
> + char old_c = NewName.at(pos);
> + char new_str[16];
> + sprintf(new_str, "%d", (int)old_c);
> + NewName = NewName.replace(pos, 1, new_str);
> + }
> +
> + return NewName;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// MCJIT helper class
>
> +//===----------------------------------------------------------------------===//
> +
> +class MCJITHelper
> +{
> +public:
> + MCJITHelper(LLVMContext& C) : Context(C), OpenModule(NULL) {}
> + ~MCJITHelper();
> +
> + Function *getFunction(const std::string FnName);
> + Module *getModuleForNewFunction();
> + void *getPointerToFunction(Function* F);
> + void *getSymbolAddress(const std::string &Name);
> + void dump();
> +
> +private:
> + typedef std::vector<Module*> ModuleVector;
> + typedef std::vector<ExecutionEngine*> EngineVector;
> +
> + LLVMContext &Context;
> + Module *OpenModule;
> + ModuleVector Modules;
> + EngineVector Engines;
> +};
> +
> +class HelpingMemoryManager : public SectionMemoryManager
> +{
> + HelpingMemoryManager(const HelpingMemoryManager&) LLVM_DELETED_FUNCTION;
> + void operator=(const HelpingMemoryManager&) LLVM_DELETED_FUNCTION;
> +
> +public:
> + HelpingMemoryManager(MCJITHelper *Helper) : MasterHelper(Helper) {}
> + virtual ~HelpingMemoryManager() {}
> +
> + /// This method returns the address of the specified symbol.
> + /// Our implementation will attempt to find symbols in other
> + /// modules associated with the MCJITHelper to cross link symbols
> + /// from one generated module to another.
> + virtual uint64_t getSymbolAddress(const std::string &Name) override;
> +private:
> + MCJITHelper *MasterHelper;
> +};
> +
> +uint64_t HelpingMemoryManager::getSymbolAddress(const std::string &Name)
> +{
> + uint64_t FnAddr = SectionMemoryManager::getSymbolAddress(Name);
> + if (FnAddr)
> + return FnAddr;
> +
> + uint64_t HelperFun = (uint64_t) MasterHelper->getSymbolAddress(Name);
> + if (!HelperFun)
> + report_fatal_error("Program used extern function '" + Name +
> + "' which could not be resolved!");
> +
> + return HelperFun;
> +}
> +
> +MCJITHelper::~MCJITHelper()
> +{
> + if (OpenModule)
> + delete OpenModule;
> + EngineVector::iterator begin = Engines.begin();
> + EngineVector::iterator end = Engines.end();
> + EngineVector::iterator it;
> + for (it = begin; it != end; ++it)
> + delete *it;
> +}
> +
> +Function *MCJITHelper::getFunction(const std::string FnName) {
> + ModuleVector::iterator begin = Modules.begin();
> + ModuleVector::iterator end = Modules.end();
> + ModuleVector::iterator it;
> + for (it = begin; it != end; ++it) {
> + Function *F = (*it)->getFunction(FnName);
> + if (F) {
> + if (*it == OpenModule)
> + return F;
> +
> + assert(OpenModule != NULL);
> +
> + // This function is in a module that has already been JITed.
> + // We need to generate a new prototype for external linkage.
> + Function *PF = OpenModule->getFunction(FnName);
> + if (PF && !PF->empty()) {
> + ErrorF("redefinition of function across modules");
> + return 0;
> + }
> +
> + // If we don't have a prototype yet, create one.
> + if (!PF)
> + PF = Function::Create(F->getFunctionType(),
> + Function::ExternalLinkage,
> + FnName,
> + OpenModule);
> + return PF;
> + }
> + }
> + return NULL;
> +}
> +
> +Module *MCJITHelper::getModuleForNewFunction() {
> + // If we have a Module that hasn't been JITed, use that.
> + if (OpenModule)
> + return OpenModule;
> +
> + // Otherwise create a new Module.
> + std::string ModName = GenerateUniqueName("mcjit_module_");
> + Module *M = new Module(ModName, Context);
> + Modules.push_back(M);
> + OpenModule = M;
> + return M;
> +}
> +
> +void *MCJITHelper::getPointerToFunction(Function* F) {
> + // See if an existing instance of MCJIT has this function.
> + EngineVector::iterator begin = Engines.begin();
> + EngineVector::iterator end = Engines.end();
> + EngineVector::iterator it;
> + for (it = begin; it != end; ++it) {
> + void *P = (*it)->getPointerToFunction(F);
> + if (P)
> + return P;
> + }
> +
> + // If we didn't find the function, see if we can generate it.
> + if (OpenModule) {
> + std::string ErrStr;
> + ExecutionEngine *NewEngine =
> EngineBuilder(std::unique_ptr<Module>(OpenModule))
> + .setErrorStr(&ErrStr)
> +
> .setMCJITMemoryManager(std::unique_ptr<HelpingMemoryManager>(new
> HelpingMemoryManager(this)))
> + .create();
> + if (!NewEngine) {
> + fprintf(stderr, "Could not create ExecutionEngine: %s\n",
> ErrStr.c_str());
> + exit(1);
> + }
> +
> + // Create a function pass manager for this engine
> + FunctionPassManager *FPM = new FunctionPassManager(OpenModule);
> +
> + // Set up the optimizer pipeline. Start with registering info about
> how the
> + // target lays out data structures.
> + OpenModule->setDataLayout(NewEngine->getDataLayout());
> + FPM->add(new DataLayoutPass());
> + // Provide basic AliasAnalysis support for GVN.
> + FPM->add(createBasicAliasAnalysisPass());
> + // Promote allocas to registers.
> + FPM->add(createPromoteMemoryToRegisterPass());
> + // Do simple "peephole" optimizations and bit-twiddling optzns.
> + FPM->add(createInstructionCombiningPass());
> + // Reassociate expressions.
> + FPM->add(createReassociatePass());
> + // Eliminate Common SubExpressions.
> + FPM->add(createGVNPass());
> + // Simplify the control flow graph (deleting unreachable blocks, etc).
> + FPM->add(createCFGSimplificationPass());
> + FPM->doInitialization();
> +
> + // For each function in the module
> + Module::iterator it;
> + Module::iterator end = OpenModule->end();
> + for (it = OpenModule->begin(); it != end; ++it) {
> + // Run the FPM on this function
> + FPM->run(*it);
> + }
> +
> + // We don't need this anymore
> + delete FPM;
> +
> + OpenModule = NULL;
> + Engines.push_back(NewEngine);
> + NewEngine->finalizeObject();
> + return NewEngine->getPointerToFunction(F);
> + }
> + return NULL;
> +}
> +
> +void *MCJITHelper::getSymbolAddress(const std::string &Name)
> +{
> + // Look for the symbol in each of our execution engines.
> + EngineVector::iterator begin = Engines.begin();
> + EngineVector::iterator end = Engines.end();
> + EngineVector::iterator it;
> + for (it = begin; it != end; ++it) {
> + uint64_t FAddr = (*it)->getFunctionAddress(Name);
> + if (FAddr) {
> + return (void *)FAddr;
> + }
> + }
> + return NULL;
> +}
> +
> +void MCJITHelper::dump()
> +{
> + ModuleVector::iterator begin = Modules.begin();
> + ModuleVector::iterator end = Modules.end();
> + ModuleVector::iterator it;
> + for (it = begin; it != end; ++it)
> + (*it)->dump();
> +}
>
> +//===----------------------------------------------------------------------===//
> // Code Generation
>
> //===----------------------------------------------------------------------===//
>
> -static Module *TheModule;
> +static MCJITHelper *JITHelper;
> static IRBuilder<> Builder(getGlobalContext());
> static std::map<std::string, Value *> NamedValues;
> -static FunctionPassManager *TheFPM;
>
> Value *ErrorV(const char *Str) {
> Error(Str);
> @@ -429,7 +669,7 @@ Value *BinaryExprAST::Codegen() {
>
> Value *CallExprAST::Codegen() {
> // Look up the name in the global module table.
> - Function *CalleeF = TheModule->getFunction(Callee);
> + Function *CalleeF = JITHelper->getFunction(Callee);
> if (CalleeF == 0)
> return ErrorV("Unknown function referenced");
>
> @@ -454,16 +694,19 @@ Function *PrototypeAST::Codegen() {
> FunctionType *FT =
> FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles,
> false);
>
> + std::string FnName = MakeLegalFunctionName(Name);
> +
> + Module *M = JITHelper->getModuleForNewFunction();
> +
> Function *F =
> - Function::Create(FT, Function::ExternalLinkage, Name, TheModule);
> + Function::Create(FT, Function::ExternalLinkage, FnName, M);
>
> // If F conflicted, there was already something named 'Name'. If it
> has a
> // body, don't allow redefinition or reextern.
> - if (F->getName() != Name) {
> + if (F->getName() != FnName) {
> // Delete the one we just made and get the existing one.
> F->eraseFromParent();
> - F = TheModule->getFunction(Name);
> -
> + F = JITHelper->getFunction(Name);
> // If F already has a body, reject this.
> if (!F->empty()) {
> ErrorF("redefinition of function");
> @@ -508,9 +751,6 @@ Function *FunctionAST::Codegen() {
> // Validate the generated code, checking for consistency.
> verifyFunction(*TheFunction);
>
> - // Optimize the function.
> - TheFPM->run(*TheFunction);
> -
> return TheFunction;
> }
>
> @@ -523,8 +763,6 @@ Function *FunctionAST::Codegen() {
> // Top-Level parsing and JIT Driver
>
> //===----------------------------------------------------------------------===//
>
> -static ExecutionEngine *TheExecutionEngine;
> -
> static void HandleDefinition() {
> if (FunctionAST *F = ParseDefinition()) {
> if (Function *LF = F->Codegen()) {
> @@ -553,9 +791,8 @@ static void HandleTopLevelExpression() {
> // Evaluate a top-level expression into an anonymous function.
> if (FunctionAST *F = ParseTopLevelExpr()) {
> if (Function *LF = F->Codegen()) {
> - TheExecutionEngine->finalizeObject();
> // JIT the function, returning a function pointer.
> - void *FPtr = TheExecutionEngine->getPointerToFunction(LF);
> + void *FPtr = JITHelper->getPointerToFunction(LF);
>
> // Cast it to the right type (takes no arguments, returns a double)
> so we
> // can call it as a native function.
> @@ -610,6 +847,7 @@ int main() {
> InitializeNativeTargetAsmPrinter();
> InitializeNativeTargetAsmParser();
> LLVMContext &Context = getGlobalContext();
> + JITHelper = new MCJITHelper(Context);
>
> // Install standard binary operators.
> // 1 is lowest precedence.
> @@ -622,51 +860,11 @@ int main() {
> fprintf(stderr, "ready> ");
> getNextToken();
>
> - // Make the module, which holds all the code.
> - std::unique_ptr<Module> Owner = make_unique<Module>("my cool jit",
> Context);
> - TheModule = Owner.get();
> -
> - // Create the JIT. This takes ownership of the module.
> - std::string ErrStr;
> - TheExecutionEngine =
> - EngineBuilder(std::move(Owner))
> - .setErrorStr(&ErrStr)
> -
> .setMCJITMemoryManager(llvm::make_unique<SectionMemoryManager>())
> - .create();
> - if (!TheExecutionEngine) {
> - fprintf(stderr, "Could not create ExecutionEngine: %s\n",
> ErrStr.c_str());
> - exit(1);
> - }
> -
> - FunctionPassManager OurFPM(TheModule);
> -
> - // Set up the optimizer pipeline. Start with registering info about
> how the
> - // target lays out data structures.
> - TheModule->setDataLayout(TheExecutionEngine->getDataLayout());
> - OurFPM.add(new DataLayoutPass());
> - // Provide basic AliasAnalysis support for GVN.
> - OurFPM.add(createBasicAliasAnalysisPass());
> - // Do simple "peephole" optimizations and bit-twiddling optzns.
> - OurFPM.add(createInstructionCombiningPass());
> - // Reassociate expressions.
> - OurFPM.add(createReassociatePass());
> - // Eliminate Common SubExpressions.
> - OurFPM.add(createGVNPass());
> - // Simplify the control flow graph (deleting unreachable blocks, etc).
> - OurFPM.add(createCFGSimplificationPass());
> -
> - OurFPM.doInitialization();
> -
> - // Set the global so the code gen can use this.
> - TheFPM = &OurFPM;
> -
> // Run the main "interpreter loop" now.
> MainLoop();
>
> - TheFPM = 0;
> -
> // Print out all of the generated code.
> - TheModule->dump();
> + JITHelper->dump();
>
> return 0;
> }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150116/19140c2e/attachment.html>
More information about the llvm-commits
mailing list