Index: llvm/trunk/docs/tutorial/BuildingAJIT1.rst =================================================================== --- llvm/trunk/docs/tutorial/BuildingAJIT1.rst +++ llvm/trunk/docs/tutorial/BuildingAJIT1.rst @@ -125,14 +125,12 @@ class KaleidoscopeJIT { private: - std::unique_ptr TM; const DataLayout DL; ObjectLinkingLayer<> ObjectLayer; IRCompileLayer CompileLayer; public: - typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandleT; Our class begins with four members: A TargetMachine, TM, which will be used @@ -152,16 +150,16 @@ object linking layer below. That's it for member variables, after that we have a single typedef: -ModuleHandle. This is the handle type that will be returned from our JIT's +ModuleHandleT. This is the handle type that will be returned from our JIT's addModule method, and can be passed to the removeModule method to remove a module. The IRCompileLayer class already provides a convenient handle type -(IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandle to this. +(IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandleT to this. .. code-block:: c++ KaleidoscopeJIT() : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); } @@ -200,7 +198,7 @@ return JITSymbol(nullptr); }); - // Build a singlton module set to hold our module. + // Build a singleton module set to hold our module. std::vector> Ms; Ms.push_back(std::move(M)); @@ -259,16 +257,16 @@ first lambda (the one defining findSymbolInLogicalDylib) will just search for JIT'd code by calling the CompileLayer's findSymbol method. If we don't find a symbol in the JIT itself we'll fall back to our second lambda, which implements -findSymbol. This will use the RTDyldMemoyrManager::getSymbolAddressInProcess +findSymbol. This will use the RTDyldMemoryManager::getSymbolAddressInProcess method to search for the symbol within the program itself. If we can't find a -symbol definition via either of these paths the JIT will refuse to accept our +symbol definition via either of these paths, the JIT will refuse to accept our module, returning a "symbol not found" error. -Now that we've built our symbol resolver we're ready to add our module to the +Now that we've built our symbol resolver, we're ready to add our module to the JIT. We do this by calling the CompileLayer's addModuleSet method [4]_. Since we only have a single Module and addModuleSet expects a collection, we will create a vector of modules and add our module as the only member. Since we -have already typedef'd our ModuleHandle type to be the same as the +have already typedef'd our ModuleHandleT type to be the same as the CompileLayer's handle type, we can return the handle from addModuleSet directly from our addModule method. @@ -304,7 +302,7 @@ entered. It is generally good to free any module that you know you won't need to call further, just to free up the resources dedicated to it. However, you don't strictly need to do this: All resources will be cleaned up when your -JIT class is destructed, if the haven't been freed before then. +JIT class is destructed, if they haven't been freed before then. This brings us to the end of Chapter 1 of Building a JIT. You now have a basic but fully functioning JIT stack that you can use to take LLVM IR and make it Index: llvm/trunk/docs/tutorial/LangImpl02.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl02.rst +++ llvm/trunk/docs/tutorial/LangImpl02.rst @@ -119,6 +119,8 @@ public: PrototypeAST(const std::string &name, std::vector Args) : Name(name), Args(std::move(Args)) {} + + const std::string &getName() const { return Name; } }; /// FunctionAST - This class represents a function definition itself. Index: llvm/trunk/docs/tutorial/LangImpl03.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl03.rst +++ llvm/trunk/docs/tutorial/LangImpl03.rst @@ -122,7 +122,7 @@ .. code-block:: c++ Value *NumberExprAST::codegen() { - return ConstantFP::get(LLVMContext, APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } In the LLVM IR, numeric constants are represented with the @@ -171,7 +171,7 @@ case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(LLVMContext), + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); @@ -270,9 +270,9 @@ Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. std::vector Doubles(Args.size(), - Type::getDoubleTy(LLVMContext)); + Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(LLVMContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); @@ -346,7 +346,7 @@ .. code-block:: c++ // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(LLVMContext, "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -533,7 +533,8 @@ ret double %calltmp } -When you quit the current demo, it dumps out the IR for the entire +When you quit the current demo (by sending an EOF via CTRL+D on Linux +or CTRL+Z and ENTER on Windows), it dumps out the IR for the entire module generated. Here you can see the big picture with all the functions referencing each other. Index: llvm/trunk/docs/tutorial/LangImpl04.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl04.rst +++ llvm/trunk/docs/tutorial/LangImpl04.rst @@ -131,33 +131,29 @@ void InitializeModuleAndPassManager(void) { // Open a new module. - Context LLVMContext; - TheModule = llvm::make_unique("my cool jit", LLVMContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheModule = llvm::make_unique("my cool jit", TheContext); // Create a new pass manager attached to it. TheFPM = llvm::make_unique(TheModule.get()); - // Provide basic AliasAnalysis support for GVN. - TheFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. - TheFPM.add(createInstructionCombiningPass()); + TheFPM->add(createInstructionCombiningPass()); // Reassociate expressions. - TheFPM.add(createReassociatePass()); + TheFPM->add(createReassociatePass()); // Eliminate Common SubExpressions. - TheFPM.add(createGVNPass()); + TheFPM->add(createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). - TheFPM.add(createCFGSimplificationPass()); + TheFPM->add(createCFGSimplificationPass()); - TheFPM.doInitialization(); + TheFPM->doInitialization(); } This code initializes the global module ``TheModule``, and the function pass manager ``TheFPM``, which is attached to ``TheModule``. Once the pass manager is set up, we use a series of "add" calls to add a bunch of LLVM passes. -In this case, we choose to add five passes: one analysis pass (alias analysis), -and four optimization passes. The passes we choose here are a pretty standard set +In this case, we choose to add four optimization passes. +The passes we choose here are a pretty standard set of "cleanup" optimizations that are useful for a wide variety of code. I won't delve into what they do but, believe me, they are a good starting place :). @@ -227,8 +223,10 @@ should evaluate and print out 3. If they define a function, they should be able to call it from the command line. -In order to do this, we first declare and initialize the JIT. This is -done by adding a global variable ``TheJIT``, and initializing it in +In order to do this, we first prepare the environment to create code for +the current native target and declare and initialize the JIT. This is +done by calling some ``InitializeNativeTarget\*`` functions and +adding a global variable ``TheJIT``, and initializing it in ``main``: .. code-block:: c++ @@ -236,7 +234,21 @@ static std::unique_ptr TheJIT; ... int main() { - .. + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + TheJIT = llvm::make_unique(); // Run the main "interpreter loop" now. @@ -245,9 +257,24 @@ return 0; } +We also need to setup the data layout for the JIT: + +.. code-block:: c++ + + void InitializeModuleAndPassManager(void) { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + + // Create a new pass manager attached to it. + TheFPM = llvm::make_unique(TheModule.get()); + ... + The KaleidoscopeJIT class is a simple JIT built specifically for these -tutorials. In later chapters we will look at how it works and extend it with -new features, but for now we will take it as given. Its API is very simple:: +tutorials, available inside the LLVM source code +at llvm-src/examples/Kaleidoscope/include/KaleidoscopeJIT.h. +In later chapters we will look at how it works and extend it with +new features, but for now we will take it as given. Its API is very simple: ``addModule`` adds an LLVM IR module to the JIT, making its functions available for execution; ``removeModule`` removes a module, freeing any memory associated with the code in that module; and ``findSymbol`` allows us @@ -554,7 +581,10 @@ found inside the JIT, it falls back to calling "``dlsym("sin")``" on the Kaleidoscope process itself. Since "``sin``" is defined within the JIT's address space, it simply patches up calls in the module to call the libm -version of ``sin`` directly. +version of ``sin`` directly. But in some cases this even goes further: +as sin and cos are names of standard math functions, the constant folder +will directly evaluate the function calls to the correct result when called +with constants like in the "``sin(1.0)``" above. In the future we'll see how tweaking this symbol resolution rule can be used to enable all sorts of useful features, from security (restricting the set of @@ -567,12 +597,21 @@ .. code-block:: c++ + #ifdef LLVM_ON_WIN32 + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT + #endif + /// putchard - putchar that takes a double and returns 0. - extern "C" double putchard(double X) { + extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } +Note, that for Windows we need to actually export the functions because +the dynamic symbol loader will use GetProcAddress to find the symbols. + Now we can produce simple output to the console by using things like: "``extern putchard(x); putchard(120);``", which prints a lowercase 'x' on the console (120 is the ASCII code for 'x'). Similar code could be Index: llvm/trunk/docs/tutorial/LangImpl05.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl05.rst +++ llvm/trunk/docs/tutorial/LangImpl05.rst @@ -103,7 +103,8 @@ IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, std::unique_ptr Else) : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - virtual Value *codegen(); + + Value *codegen() override; }; The AST node just has pointers to the various subexpressions. @@ -290,9 +291,9 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(LLVMContext, APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); This code is straightforward and similar to what we saw before. We emit the expression for the condition, then compare that value to zero to get @@ -305,9 +306,9 @@ // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = - BasicBlock::Create(LLVMContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(LLVMContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(LLVMContext, "ifcont"); + BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -400,7 +401,7 @@ TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(LLVMContext), 2, "iftmp"); + Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -433,7 +434,7 @@ :: - extern putchard(char) + extern putchard(char); def printstar(n) for i = 1, i < n, 1.0 in putchard(42); # ascii 42 = '*' @@ -500,7 +501,8 @@ std::unique_ptr Body) : VarName(VarName), Start(std::move(Start)), End(std::move(End)), Step(std::move(Step)), Body(std::move(Body)) {} - virtual Value *codegen(); + + Value *codegen() override; }; Parser Extensions for the 'for' Loop @@ -561,6 +563,27 @@ std::move(Body)); } +And again we hook it up as a primary expression: + +.. code-block:: c++ + + static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + } + } + LLVM IR for the 'for' Loop -------------------------- @@ -610,7 +633,8 @@ Value *ForExprAST::codegen() { // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->codegen(); - if (StartVal == 0) return 0; + if (!StartVal) + return nullptr; With this out of the way, the next step is to set up the LLVM basic block for the start of the loop body. In the case above, the whole loop @@ -625,7 +649,7 @@ Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); BasicBlock *LoopBB = - BasicBlock::Create(LLVMContext, "loop", TheFunction); + BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -642,7 +666,7 @@ Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. - PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(LLVMContext), + PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName.c_str()); Variable->addIncoming(StartVal, PreheaderBB); @@ -693,7 +717,7 @@ return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(LLVMContext, APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); @@ -710,9 +734,9 @@ if (!EndCond) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(LLVMContext, APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); Finally, we evaluate the exit value of the loop, to determine whether the loop should exit. This mirrors the condition evaluation for the @@ -723,7 +747,7 @@ // Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(LLVMContext, "afterloop", TheFunction); + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -751,7 +775,7 @@ NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(LLVMContext)); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } The final code handles various cleanups: now that we have the "NextVar" @@ -772,7 +796,7 @@ ================= Here is the complete code listing for our running example, enhanced with -the if/then/else and for expressions.. To build this example, use: +the if/then/else and for expressions. To build this example, use: .. code-block:: bash Index: llvm/trunk/docs/tutorial/LangImpl06.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl06.rst +++ llvm/trunk/docs/tutorial/LangImpl06.rst @@ -31,7 +31,7 @@ ================================ The "operator overloading" that we will add to Kaleidoscope is more -general than languages like C++. In C++, you are only allowed to +general than in languages like C++. In C++, you are only allowed to redefine existing operators: you can't programmatically change the grammar, introduce new operators, change precedence levels, etc. In this chapter, we will add this capability to Kaleidoscope, which will let the @@ -41,8 +41,8 @@ is to show the power and flexibility of using a hand-written parser. Thus far, the parser we have been implementing uses recursive descent for most parts of the grammar and operator precedence parsing for the -expressions. See `Chapter 2 `_ for details. Without -using operator precedence parsing, it would be very difficult to allow +expressions. See `Chapter 2 `_ for details. By +using operator precedence parsing, it is very easy to allow the programmer to introduce new operators into the grammar: the grammar is dynamically extensible as the JIT runs. @@ -143,17 +143,18 @@ : Name(name), Args(std::move(Args)), IsOperator(IsOperator), Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } bool isBinaryOp() const { return IsOperator && Args.size() == 2; } char getOperatorName() const { assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size()-1]; + return Name[Name.size() - 1]; } unsigned getBinaryPrecedence() const { return Precedence; } - - Function *codegen(); }; Basically, in addition to knowing a name for the prototype, we now keep @@ -194,7 +195,7 @@ // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); + return LogErrorP("Invalid precedence: must be 1..100"); BinaryPrecedence = (unsigned)NumVal; getNextToken(); } @@ -225,7 +226,7 @@ seen a lot of similar code in the past. One interesting part about the code above is the couple lines that set up ``FnName`` for binary operators. This builds names like "binary@" for a newly defined "@" -operator. This then takes advantage of the fact that symbol names in the +operator. It then takes advantage of the fact that symbol names in the LLVM symbol table are allowed to have any character in them, including embedded nul characters. @@ -251,7 +252,7 @@ case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(LLVMContext), + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; @@ -259,7 +260,7 @@ // If it wasn't a builtin binary operator, it must be a user defined one. Emit // a call to it. - Function *F = TheModule->getFunction(std::string("binary") + Op); + Function *F = getFunction(std::string("binary") + Op); assert(F && "binary operator not found!"); Value *Ops[2] = { L, R }; @@ -277,22 +278,21 @@ .. code-block:: c++ Function *FunctionAST::codegen() { - NamedValues.clear(); - - Function *TheFunction = Proto->codegen(); + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); + Function *TheFunction = getFunction(P.getName()); if (!TheFunction) return nullptr; // If this is an operator, install it. - if (Proto->isBinaryOp()) - BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(LLVMContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); - - if (Value *RetVal = Body->codegen()) { - ... + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + ... Basically, before codegening a function, if it is a user-defined operator, we register it in the precedence table. This allows the binary @@ -323,7 +323,8 @@ public: UnaryExprAST(char Opcode, std::unique_ptr Operand) : Opcode(Opcode), Operand(std::move(Operand)) {} - virtual Value *codegen(); + + Value *codegen() override; }; This AST node is very simple and obvious by now. It directly mirrors the @@ -345,7 +346,7 @@ int Opc = CurTok; getNextToken(); if (auto Operand = ParseUnary()) - return llvm::unique_ptr(Opc, std::move(Operand)); + return llvm::make_unique(Opc, std::move(Operand)); return nullptr; } @@ -433,7 +434,7 @@ if (!OperandV) return nullptr; - Function *F = TheModule->getFunction(std::string("unary")+Opcode); + Function *F = getFunction(std::string("unary") + Opcode); if (!F) return LogErrorV("Unknown unary operator"); @@ -461,7 +462,7 @@ declare double @printd(double) ready> def binary : 1 (x y) 0; # Low-precedence operator that ignores operands. - .. + ... ready> printd(123) : printd(456) : printd(789); 123.000000 456.000000 @@ -518,10 +519,9 @@ :: - ready> - - extern putchard(char) - def printdensity(d) + ready> extern putchard(char); + ... + ready> def printdensity(d) if d > 8 then putchard(32) # ' ' else if d > 4 then @@ -538,9 +538,9 @@ Evaluated to 0.000000 Based on these simple primitive operations, we can start to define more -interesting things. For example, here's a little function that solves -for the number of iterations it takes a function in the complex plane to -converge: +interesting things. For example, here's a little function that determines +the number of iterations it takes for a certain function in the complex +plane to diverge: :: @@ -742,7 +742,7 @@ ================= Here is the complete code listing for our running example, enhanced with -the if/then/else and for expressions.. To build this example, use: +the support for user-defined operators. To build this example, use: .. code-block:: bash Index: llvm/trunk/docs/tutorial/LangImpl07.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl07.rst +++ llvm/trunk/docs/tutorial/LangImpl07.rst @@ -327,7 +327,7 @@ static std::map NamedValues; -Also, since we will need to create these alloca's, we'll use a helper +Also, since we will need to create these allocas, we'll use a helper function that ensures that the allocas are created in the entry block of the function: @@ -339,7 +339,7 @@ const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(LLVMContext), 0, + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } @@ -348,7 +348,7 @@ alloca with the expected name and returns it. Because all values in Kaleidoscope are doubles, there is no need to pass in a type to use. -With this in place, the first functionality change we want to make is to +With this in place, the first functionality change we want to make belongs to variable references. In our new scheme, variables live on the stack, so code generating a reference to them actually needs to produce a load from the stack slot: @@ -377,7 +377,7 @@ // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - // Emit the start code first, without 'variable' in scope. + // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->codegen(); if (!StartVal) return nullptr; @@ -408,21 +408,25 @@ .. code-block:: c++ - /// CreateArgumentAllocas - Create an alloca for each argument and register the - /// argument in the symbol table so that references to it will succeed. - void PrototypeAST::CreateArgumentAllocas(Function *F) { - Function::arg_iterator AI = F->arg_begin(); - for (unsigned Idx = 0, e = Args.size(); Idx != e; ++Idx, ++AI) { + Function *FunctionAST::codegen() { + ... + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. - Builder.CreateStore(AI, Alloca); + Builder.CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. - NamedValues[Args[Idx]] = Alloca; + NamedValues[Arg.getName()] = Alloca; } - } + + if (Value *RetVal = Body->codegen()) { + ... For each argument, we make an alloca, store the input value to the function into the alloca, and register the alloca as the memory location @@ -434,15 +438,13 @@ .. code-block:: c++ - // Set up the optimizer pipeline. Start with registering info about how the - // target lays out data structures. - OurFPM.add(new DataLayout(*TheExecutionEngine->getDataLayout())); // Promote allocas to registers. - OurFPM.add(createPromoteMemoryToRegisterPass()); + TheFPM->add(createPromoteMemoryToRegisterPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. - OurFPM.add(createInstructionCombiningPass()); + TheFPM->add(createInstructionCombiningPass()); // Reassociate expressions. - OurFPM.add(createReassociatePass()); + TheFPM->add(createReassociatePass()); + ... It is interesting to see what the code looks like before and after the mem2reg optimization runs. For example, this is the before/after code @@ -454,7 +456,7 @@ entry: %x1 = alloca double store double %x, double* %x1 - %x2 = load double* %x1 + %x2 = load double, double* %x1 %cmptmp = fcmp ult double %x2, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double %ifcond = fcmp one double %booltmp, 0.000000e+00 @@ -464,10 +466,10 @@ br label %ifcont else: ; preds = %entry - %x3 = load double* %x1 + %x3 = load double, double* %x1 %subtmp = fsub double %x3, 1.000000e+00 %calltmp = call double @fib(double %subtmp) - %x4 = load double* %x1 + %x4 = load double, double* %x1 %subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double @fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 @@ -677,10 +679,10 @@ public: VarExprAST(std::vector>> VarNames, - std::unique_ptr body) - : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} - virtual Value *codegen(); + Value *codegen() override; }; var/in allows a list of names to be defined all at once, and each name @@ -812,7 +814,7 @@ if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(LLVMContext, APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); Index: llvm/trunk/docs/tutorial/LangImpl09.rst =================================================================== --- llvm/trunk/docs/tutorial/LangImpl09.rst +++ llvm/trunk/docs/tutorial/LangImpl09.rst @@ -18,7 +18,7 @@ translate from binary and the state of the machine back to the source that the programmer wrote. In LLVM we generally use a format called `DWARF `_. DWARF is a compact encoding -that represents types, source locations, and variable locations. +that represents types, source locations, and variable locations. The short summary of this chapter is that we'll go through the various things you have to add to a programming language to @@ -94,14 +94,14 @@ return; @@ -1184,7 +1183,6 @@ int main() { BinopPrecedence['*'] = 40; // highest. - + // Prime the first token. - fprintf(stderr, "ready> "); getNextToken(); - + Lastly we're going to disable all of the optimization passes and the JIT so that the only thing that happens after we're done parsing and generating -code is that the llvm IR goes to standard error: +code is that the LLVM IR goes to standard error: .. code-block:: udiff @@ -140,7 +140,7 @@ - + #endif OurFPM.doInitialization(); - + // Set the global so the code gen can use this. This relatively small set of changes get us to the point that we can compile @@ -166,8 +166,8 @@ Similar to the ``IRBuilder`` class we have a `DIBuilder `_ class -that helps in constructing debug metadata for an llvm IR file. It -corresponds 1:1 similarly to ``IRBuilder`` and llvm IR, but with nicer names. +that helps in constructing debug metadata for an LLVM IR file. It +corresponds 1:1 similarly to ``IRBuilder`` and LLVM IR, but with nicer names. Using it does require that you be more familiar with DWARF terminology than you needed to be with ``IRBuilder`` and ``Instruction`` names, but if you read through the general documentation on the @@ -194,7 +194,7 @@ } KSDbgInfo; DIType *DebugInfo::getDoubleTy() { - if (DblTy.isValid()) + if (DblTy) return DblTy; DblTy = DBuilder->createBasicType("double", 64, 64, dwarf::DW_ATE_float); @@ -214,7 +214,7 @@ compile unit for a language called Kaleidoscope we used the language constant for C. This is because a debugger wouldn't necessarily understand the calling conventions or default ABI for a language it doesn't recognize -and we follow the C ABI in our llvm code generation so it's the closest +and we follow the C ABI in our LLVM code generation so it's the closest thing to accurate. This ensures we can actually call functions from the debugger and have them execute. Secondly, you'll see the "fib.ks" in the call to ``createCompileUnit``. This is a default hard coded value since @@ -259,10 +259,11 @@ unsigned LineNo = 0; unsigned ScopeLine = 0; DISubprogram *SP = DBuilder->createFunction( - FContext, Name, StringRef(), Unit, LineNo, - CreateFunctionType(Args.size(), Unit), false /* internal linkage */, - true /* definition */, ScopeLine, DINode::FlagPrototyped, false); - F->setSubprogram(SP); + FContext, P.getName(), StringRef(), Unit, LineNo, + CreateFunctionType(TheFunction->arg_size(), Unit), + false /* internal linkage */, true /* definition */, ScopeLine, + DINode::FlagPrototyped, false); + TheFunction->setSubprogram(SP); and we now have an DISubprogram that contains a reference to all of our metadata for the function. @@ -326,10 +327,9 @@ giving us locations for each of our expressions and variables. -From this we can make sure to tell ``DIBuilder`` when we're at a new source -location so it can use that when we generate the rest of our code and make -sure that each instruction has source location information. We do this -by constructing another small function: +To make sure that every instruction gets proper source location information, +we have to tell ``Builder`` whenever we're at a new source location. +We use a small helper function for this: .. code-block:: c++ @@ -343,40 +343,23 @@ DebugLoc::get(AST->getLine(), AST->getCol(), Scope)); } -that both tells the main ``IRBuilder`` where we are, but also what scope -we're in. Since we've just created a function above we can either be in -the main file scope (like when we created our function), or now we can be -in the function scope we just created. To represent this we create a stack -of scopes: +This both tells the main ``IRBuilder`` where we are, but also what scope +we're in. The scope can either be on compile-unit level or be the nearest +enclosing lexical block like the current function. +To represent this we create a stack of scopes: .. code-block:: c++ std::vector LexicalBlocks; - std::map FnScopeMap; - -and keep a map of each function to the scope that it represents (an -DISubprogram is also an DIScope). - -Then we make sure to: - -.. code-block:: c++ - - KSDbgInfo.emitLocation(this); -emit the location every time we start to generate code for a new AST, and -also: +and push the scope (function) to the top of the stack when we start +generating the code for each function: .. code-block:: c++ - KSDbgInfo.FnScopeMap[this] = SP; - -store the scope (function) when we create it and use it: - - KSDbgInfo.LexicalBlocks.push_back(&KSDbgInfo.FnScopeMap[Proto]); - -when we start generating the code for each function. + KSDbgInfo.LexicalBlocks.push_back(SP); -also, don't forget to pop the scope back off of your scope stack at the +Also, we may not forget to pop the scope back off of the scope stack at the end of the code generation for the function: .. code-block:: c++ @@ -385,6 +368,13 @@ // unconditionally. KSDbgInfo.LexicalBlocks.pop_back(); +Then we make sure to emit the location every time we start to generate code +for a new AST object: + +.. code-block:: c++ + + KSDbgInfo.emitLocation(this); + Variables ========= @@ -392,25 +382,37 @@ we have in scope. Let's get our function arguments set up so we can get decent backtraces and see how our functions are being called. It isn't a lot of code, and we generally handle it when we're creating the -argument allocas in ``PrototypeAST::CreateArgumentAllocas``. +argument allocas in ``FunctionAST::codegen``. .. code-block:: c++ - DIScope *Scope = KSDbgInfo.LexicalBlocks.back(); - DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU.getFilename(), - KSDbgInfo.TheCU.getDirectory()); - DILocalVariable D = DBuilder->createParameterVariable( - Scope, Args[Idx], Idx + 1, Unit, Line, KSDbgInfo.getDoubleTy(), true); + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + unsigned ArgIdx = 0; + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Create a debug descriptor for the variable. + DILocalVariable *D = DBuilder->createParameterVariable( + SP, Arg.getName(), ++ArgIdx, Unit, LineNo, KSDbgInfo.getDoubleTy(), + true); + + DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), + DebugLoc::get(LineNo, 0, SP), + Builder.GetInsertBlock()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + - DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), - DebugLoc::get(Line, 0, Scope), - Builder.GetInsertBlock()); - -Here we're doing a few things. First, we're grabbing our current scope -for the variable so we can say what range of code our variable is valid -through. Second, we're creating the variable, giving it the scope, +Here we're first creating the variable, giving it the scope (``SP``), the name, source location, type, and since it's an argument, the argument -index. Third, we create an ``lvm.dbg.declare`` call to indicate at the IR +index. Next, we create an ``lvm.dbg.declare`` call to indicate at the IR level that we've got a variable in an alloca (and it gives a starting location for the variable), and setting a source location for the beginning of the scope on the declare. @@ -420,7 +422,7 @@ in the past. In this case we need to do a little bit of a hack to avoid generating line information for the function prologue so that the debugger knows to skip over those instructions when setting a breakpoint. So in -``FunctionAST::CodeGen`` we add a couple of lines: +``FunctionAST::CodeGen`` we add some more lines: .. code-block:: c++ @@ -434,7 +436,7 @@ .. code-block:: c++ - KSDbgInfo.emitLocation(Body); + KSDbgInfo.emitLocation(Body.get()); With this we have enough debug information to set breakpoints in functions, print out argument variables, and call functions. Not too bad for just a Index: llvm/trunk/examples/Kaleidoscope/Chapter2/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter2/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter2/toy.cpp @@ -140,6 +140,8 @@ public: PrototypeAST(const std::string &Name, std::vector Args) : Name(Name), Args(std::move(Args)) {} + + const std::string &getName() const { return Name; } }; /// FunctionAST - This class represents a function definition itself. Index: llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter4/toy.cpp @@ -650,14 +650,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/Chapter5/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter5/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter5/toy.cpp @@ -622,7 +622,7 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); @@ -736,7 +736,7 @@ if (!EndCond) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); @@ -924,14 +924,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/Chapter6/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter6/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter6/toy.cpp @@ -567,7 +567,7 @@ // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); + return LogErrorP("Invalid precedence: must be 1..100"); BinaryPrecedence = (unsigned)NumVal; getNextToken(); } @@ -734,7 +734,7 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); @@ -848,7 +848,7 @@ if (!EndCond) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); @@ -1043,14 +1043,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/Chapter7/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter7/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter7/toy.cpp @@ -639,7 +639,7 @@ // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); + return LogErrorP("Invalid precedence: must be 1..100"); BinaryPrecedence = (unsigned)NumVal; getNextToken(); } @@ -840,7 +840,7 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); @@ -963,7 +963,7 @@ Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); Builder.CreateStore(NextVar, Alloca); - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); @@ -1115,6 +1115,8 @@ // Create a new pass manager attached to it. TheFPM = llvm::make_unique(TheModule.get()); + // Promote allocas to registers. + TheFPM->add(createPromoteMemoryToRegisterPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. TheFPM->add(createInstructionCombiningPass()); // Reassociate expressions. @@ -1210,14 +1212,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/Chapter8/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter8/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter8/toy.cpp @@ -642,7 +642,7 @@ // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); + return LogErrorP("Invalid precedence: must be 1..100"); BinaryPrecedence = (unsigned)NumVal; getNextToken(); } @@ -841,7 +841,7 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); @@ -964,7 +964,7 @@ Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); Builder.CreateStore(NextVar, Alloca); - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); @@ -1173,14 +1173,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/Chapter9/toy.cpp =================================================================== --- llvm/trunk/examples/Kaleidoscope/Chapter9/toy.cpp +++ llvm/trunk/examples/Kaleidoscope/Chapter9/toy.cpp @@ -756,7 +756,7 @@ // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); + return LogErrorP("Invalid precedence: must be 1..100"); BinaryPrecedence = (unsigned)NumVal; getNextToken(); } @@ -1004,7 +1004,7 @@ if (!CondV) return nullptr; - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. CondV = Builder.CreateFCmpONE( CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); @@ -1129,7 +1129,7 @@ Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); Builder.CreateStore(NextVar, Alloca); - // Convert condition to a bool by comparing equal to 0.0. + // Convert condition to a bool by comparing non-equal to 0.0. EndCond = Builder.CreateFCmpONE( EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); @@ -1379,14 +1379,20 @@ // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + /// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { +extern "C" DLLEXPORT double putchard(double X) { fputc((char)X, stderr); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { +extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; } Index: llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h =================================================================== --- llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h +++ llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h @@ -97,17 +97,40 @@ } JITSymbol findMangledSymbol(const std::string &Name) { +#ifdef LLVM_ON_WIN32 + // The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported + // flag to decide whether a symbol will be visible or not, when we call + // IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true. + // + // But for Windows COFF objects, this flag is currently never set. + // For a potential solution see: https://reviews.llvm.org/rL258665 + // For now, we allow non-exported symbols on Windows as a workaround. + const bool ExportedSymbolsOnly = false; +#else + const bool ExportedSymbolsOnly = true; +#endif + // Search modules in reverse order: from last added to first added. // This is the opposite of the usual search order for dlsym, but makes more // sense in a REPL where we want to bind to the newest available definition. for (auto H : make_range(ModuleHandles.rbegin(), ModuleHandles.rend())) - if (auto Sym = CompileLayer.findSymbolIn(H, Name, true)) + if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly)) return Sym; // If we can't find the symbol in the JIT, try looking in the host process. if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name)) return JITSymbol(SymAddr, JITSymbolFlags::Exported); +#ifdef LLVM_ON_WIN32 + // For Windows retry without "_" at begining, as RTDyldMemoryManager uses + // GetProcAddress and standard libraries like msvcrt.dll use names + // with and without "_" (for example "_itoa" but "sin"). + if (Name.length() > 2 && Name[0] == '_') + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1))) + return JITSymbol(SymAddr, JITSymbolFlags::Exported); +#endif + return nullptr; }