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