X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=examples%2FKaleidoscope%2FOrc%2Ffully_lazy%2Ftoy.cpp;h=877a7262e9125fe6c2f4fa38b5dd64a347dd4b4e;hp=678e687cea8a1a01e0707adaaf6b9f747d51ab46;hb=166aa4459f303c426f0eeccad2a066fefccf4314;hpb=cdc4c07360f60fbda54fda96b3496264f1dc434d diff --git a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp b/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp index 678e687cea8..877a7262e91 100644 --- a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp +++ b/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp @@ -1,6 +1,7 @@ #include "llvm/Analysis/Passes.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" @@ -20,7 +21,9 @@ #include #include #include + using namespace llvm; +using namespace llvm::orc; //===----------------------------------------------------------------------===// // Lexer @@ -36,14 +39,14 @@ enum Token { // primary tok_identifier = -4, tok_number = -5, - + // control tok_if = -6, tok_then = -7, tok_else = -8, tok_for = -9, tok_in = -10, - + // operators tok_binary = -11, tok_unary = -12, - + // var definition tok_var = -13 }; @@ -84,7 +87,7 @@ static int gettok() { LastChar = getchar(); } while (isdigit(LastChar) || LastChar == '.'); - NumVal = strtod(NumStr.c_str(), 0); + NumVal = strtod(NumStr.c_str(), nullptr); return tok_number; } @@ -92,11 +95,11 @@ static int gettok() { // Comment until end of line. do LastChar = getchar(); while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - + if (LastChar != EOF) return gettok(); } - + // Check for end of file. Don't eat the EOF. if (LastChar == EOF) return tok_eof; @@ -137,7 +140,7 @@ struct VariableExprAST : public ExprAST { /// UnaryExprAST - Expression class for a unary operator. struct UnaryExprAST : public ExprAST { - UnaryExprAST(char Opcode, std::unique_ptr Operand) + UnaryExprAST(char Opcode, std::unique_ptr Operand) : Opcode(std::move(Opcode)), Operand(std::move(Operand)) {} Value *IRGen(IRGenContext &C) const override; @@ -149,7 +152,7 @@ struct UnaryExprAST : public ExprAST { /// BinaryExprAST - Expression class for a binary operator. struct BinaryExprAST : public ExprAST { BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) + std::unique_ptr RHS) : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} Value *IRGen(IRGenContext &C) const override; @@ -221,7 +224,7 @@ struct PrototypeAST { 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]; @@ -265,7 +268,7 @@ static std::map BinopPrecedence; static int GetTokPrecedence() { if (!isascii(CurTok)) return -1; - + // Make sure it's a declared binop. int TokPrec = BinopPrecedence[CurTok]; if (TokPrec <= 0) return -1; @@ -291,12 +294,12 @@ static std::unique_ptr ParseExpression(); /// ::= identifier '(' expression* ')' static std::unique_ptr ParseIdentifierExpr() { std::string IdName = IdentifierStr; - + getNextToken(); // eat identifier. - + if (CurTok != '(') // Simple variable ref. return llvm::make_unique(IdName); - + // Call. getNextToken(); // eat ( std::vector> Args; @@ -316,7 +319,7 @@ static std::unique_ptr ParseIdentifierExpr() { // Eat the ')'. getNextToken(); - + return llvm::make_unique(IdName, std::move(Args)); } @@ -333,7 +336,7 @@ static std::unique_ptr ParseParenExpr() { auto V = ParseExpression(); if (!V) return nullptr; - + if (CurTok != ')') return ErrorU("expected ')'"); getNextToken(); // eat ). @@ -343,29 +346,29 @@ static std::unique_ptr ParseParenExpr() { /// ifexpr ::= 'if' expression 'then' expression 'else' expression static std::unique_ptr ParseIfExpr() { getNextToken(); // eat the if. - + // condition. auto Cond = ParseExpression(); if (!Cond) return nullptr; - + if (CurTok != tok_then) return ErrorU("expected then"); getNextToken(); // eat the then - + auto Then = ParseExpression(); if (!Then) return nullptr; - + if (CurTok != tok_else) return ErrorU("expected else"); - + getNextToken(); - + auto Else = ParseExpression(); if (!Else) return nullptr; - + return llvm::make_unique(std::move(Cond), std::move(Then), std::move(Else)); } @@ -376,26 +379,25 @@ static std::unique_ptr ParseForExpr() { if (CurTok != tok_identifier) return ErrorU("expected identifier after for"); - + std::string IdName = IdentifierStr; getNextToken(); // eat identifier. - + if (CurTok != '=') return ErrorU("expected '=' after for"); getNextToken(); // eat '='. - - + auto Start = ParseExpression(); if (!Start) return nullptr; if (CurTok != ',') return ErrorU("expected ',' after for start value"); getNextToken(); - + auto End = ParseExpression(); if (!End) return nullptr; - + // The step value is optional. std::unique_ptr Step; if (CurTok == ',') { @@ -404,11 +406,11 @@ static std::unique_ptr ParseForExpr() { if (!Step) return nullptr; } - + if (CurTok != tok_in) return ErrorU("expected 'in' after for"); getNextToken(); // eat 'in'. - + auto Body = ParseExpression(); if (Body) return nullptr; @@ -417,7 +419,7 @@ static std::unique_ptr ParseForExpr() { std::move(Step), std::move(Body)); } -/// varexpr ::= 'var' identifier ('=' expression)? +/// varexpr ::= 'var' identifier ('=' expression)? // (',' identifier ('=' expression)?)* 'in' expression static std::unique_ptr ParseVarExpr() { getNextToken(); // eat the var. @@ -427,7 +429,7 @@ static std::unique_ptr ParseVarExpr() { // At least one variable name is required. if (CurTok != tok_identifier) return ErrorU("expected identifier after var"); - + while (1) { std::string Name = IdentifierStr; getNextToken(); // eat identifier. @@ -436,31 +438,31 @@ static std::unique_ptr ParseVarExpr() { std::unique_ptr Init; if (CurTok == '=') { getNextToken(); // eat the '='. - + Init = ParseExpression(); if (!Init) return nullptr; } - + VarBindings.push_back(VarExprAST::Binding(Name, std::move(Init))); - + // End of var list, exit loop. if (CurTok != ',') break; getNextToken(); // eat the ','. - + if (CurTok != tok_identifier) return ErrorU("expected identifier list after var"); } - + // At this point, we have to have 'in'. if (CurTok != tok_in) return ErrorU("expected 'in' keyword after 'var'"); getNextToken(); // eat 'in'. - + auto Body = ParseExpression(); if (!Body) return nullptr; - + return llvm::make_unique(std::move(VarBindings), std::move(Body)); } @@ -490,7 +492,7 @@ static std::unique_ptr ParseUnary() { // If the current token is not an operator, it must be a primary expr. if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') return ParsePrimary(); - + // If this is a unary operator, read it. int Opc = CurTok; getNextToken(); @@ -506,21 +508,21 @@ static std::unique_ptr ParseBinOpRHS(int ExprPrec, // If this is a binop, find its precedence. while (1) { int TokPrec = GetTokPrecedence(); - + // If this is a binop that binds at least as tightly as the current binop, // consume it, otherwise we are done. if (TokPrec < ExprPrec) return LHS; - + // Okay, we know this is a binop. int BinOp = CurTok; getNextToken(); // eat binop - + // Parse the unary expression after the binary operator. auto RHS = ParseUnary(); if (!RHS) return nullptr; - + // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. int NextPrec = GetTokPrecedence(); @@ -529,7 +531,7 @@ static std::unique_ptr ParseBinOpRHS(int ExprPrec, if (!RHS) return nullptr; } - + // Merge LHS/RHS. LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); } @@ -542,7 +544,7 @@ static std::unique_ptr ParseExpression() { auto LHS = ParseUnary(); if (!LHS) return nullptr; - + return ParseBinOpRHS(0, std::move(LHS)); } @@ -552,10 +554,10 @@ static std::unique_ptr ParseExpression() { /// ::= unary LETTER (id) static std::unique_ptr ParsePrototype() { std::string FnName; - + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. unsigned BinaryPrecedence = 30; - + switch (CurTok) { default: return ErrorU("Expected function name in prototype"); @@ -581,7 +583,7 @@ static std::unique_ptr ParsePrototype() { FnName += (char)CurTok; Kind = 2; getNextToken(); - + // Read the precedence if present. if (CurTok == tok_number) { if (NumVal < 1 || NumVal > 100) @@ -591,23 +593,23 @@ static std::unique_ptr ParsePrototype() { } break; } - + if (CurTok != '(') return ErrorU("Expected '(' in prototype"); - + std::vector ArgNames; while (getNextToken() == tok_identifier) ArgNames.push_back(IdentifierStr); if (CurTok != ')') return ErrorU("Expected ')' in prototype"); - + // success. getNextToken(); // eat ')'. - + // Verify right number of names for operator. if (Kind && ArgNames.size() != Kind) return ErrorU("Invalid number of operands for operator"); - + return llvm::make_unique(FnName, std::move(ArgNames), Kind != 0, BinaryPrecedence); } @@ -680,14 +682,18 @@ std::string MakeLegalFunctionName(std::string Name) class SessionContext { public: - SessionContext(LLVMContext &C) : Context(C) {} + SessionContext(LLVMContext &C) + : Context(C), TM(EngineBuilder().selectTarget()) {} LLVMContext& getLLVMContext() const { return Context; } + TargetMachine& getTarget() { return *TM; } void addPrototypeAST(std::unique_ptr P); PrototypeAST* getPrototypeAST(const std::string &Name); - std::map> FunctionDefs; private: typedef std::map> PrototypeMap; + LLVMContext &Context; + std::unique_ptr TM; + PrototypeMap Prototypes; }; @@ -709,7 +715,9 @@ public: : Session(S), M(new Module(GenerateUniqueName("jit_module_"), Session.getLLVMContext())), - Builder(Session.getLLVMContext()) {} + Builder(Session.getLLVMContext()) { + M->setDataLayout(Session.getTarget().createDataLayout()); + } SessionContext& getSession() { return Session; } Module& getM() const { return *M; } @@ -739,7 +747,7 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, + return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, VarName.c_str()); } @@ -751,7 +759,7 @@ Value *VariableExprAST::IRGen(IRGenContext &C) const { // Look this variable up in the function. Value *V = C.NamedValues[Name]; - if (V == 0) + if (!V) return ErrorP("Unknown variable name '" + Name + "'"); // Load the value. @@ -774,7 +782,7 @@ Value *BinaryExprAST::IRGen(IRGenContext &C) const { // Special case '=' because we don't want to emit the LHS as an expression. if (Op == '=') { // Assignment requires the LHS to be an identifier. - auto LHSVar = static_cast(*LHS); + auto &LHSVar = static_cast(*LHS); // Codegen the RHS. Value *Val = RHS->IRGen(C); if (!Val) return nullptr; @@ -786,11 +794,11 @@ Value *BinaryExprAST::IRGen(IRGenContext &C) const { } return ErrorP("Unknown variable name"); } - + Value *L = LHS->IRGen(C); Value *R = RHS->IRGen(C); if (!L || !R) return nullptr; - + switch (Op) { case '+': return C.getBuilder().CreateFAdd(L, R, "addtmp"); case '-': return C.getBuilder().CreateFSub(L, R, "subtmp"); @@ -803,7 +811,7 @@ Value *BinaryExprAST::IRGen(IRGenContext &C) const { "booltmp"); default: break; } - + // If it wasn't a builtin binary operator, it must be a user defined one. Emit // a call to it. std::string FnName = MakeLegalFunctionName(std::string("binary")+Op); @@ -811,7 +819,7 @@ Value *BinaryExprAST::IRGen(IRGenContext &C) const { Value *Ops[] = { L, R }; return C.getBuilder().CreateCall(F, Ops, "binop"); } - + return ErrorP("Unknown binary operator"); } @@ -827,7 +835,7 @@ Value *CallExprAST::IRGen(IRGenContext &C) const { ArgsV.push_back(Args[i]->IRGen(C)); if (!ArgsV.back()) return nullptr; } - + return C.getBuilder().CreateCall(CalleeF, ArgsV, "calltmp"); } @@ -837,49 +845,49 @@ Value *CallExprAST::IRGen(IRGenContext &C) const { Value *IfExprAST::IRGen(IRGenContext &C) const { Value *CondV = Cond->IRGen(C); if (!CondV) return nullptr; - + // Convert condition to a bool by comparing equal to 0.0. - ConstantFP *FPZero = + ConstantFP *FPZero = ConstantFP::get(C.getLLVMContext(), APFloat(0.0)); CondV = C.getBuilder().CreateFCmpONE(CondV, FPZero, "ifcond"); - + Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - + // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = BasicBlock::Create(C.getLLVMContext(), "then", TheFunction); BasicBlock *ElseBB = BasicBlock::Create(C.getLLVMContext(), "else"); BasicBlock *MergeBB = BasicBlock::Create(C.getLLVMContext(), "ifcont"); - + C.getBuilder().CreateCondBr(CondV, ThenBB, ElseBB); - + // Emit then value. C.getBuilder().SetInsertPoint(ThenBB); - + Value *ThenV = Then->IRGen(C); if (!ThenV) return nullptr; - + C.getBuilder().CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. ThenBB = C.getBuilder().GetInsertBlock(); - + // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); C.getBuilder().SetInsertPoint(ElseBB); - + Value *ElseV = Else->IRGen(C); if (!ElseV) return nullptr; - + C.getBuilder().CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. ElseBB = C.getBuilder().GetInsertBlock(); - + // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); C.getBuilder().SetInsertPoint(MergeBB); PHINode *PN = C.getBuilder().CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); - + PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; @@ -892,7 +900,7 @@ Value *ForExprAST::IRGen(IRGenContext &C) const { // start = startexpr // store start -> var // goto loop - // loop: + // loop: // ... // bodyexpr // ... @@ -905,40 +913,40 @@ Value *ForExprAST::IRGen(IRGenContext &C) const { // store nextvar -> var // br endcond, loop, endloop // outloop: - + Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - + // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->IRGen(C); if (!StartVal) return nullptr; - + // Store the value into the alloca. C.getBuilder().CreateStore(StartVal, Alloca); - + // Make the new basic block for the loop header, inserting after current // block. BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - + // Insert an explicit fall through from the current block to the LoopBB. C.getBuilder().CreateBr(LoopBB); // Start insertion in LoopBB. C.getBuilder().SetInsertPoint(LoopBB); - + // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. AllocaInst *OldVal = C.NamedValues[VarName]; C.NamedValues[VarName] = Alloca; - + // Emit the body of the loop. This, like any other expr, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (!Body->IRGen(C)) return nullptr; - + // Emit the step value. Value *StepVal; if (Step) { @@ -948,52 +956,51 @@ Value *ForExprAST::IRGen(IRGenContext &C) const { // If not specified, use 1.0. StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); } - + // Compute the end condition. Value *EndCond = End->IRGen(C); - if (EndCond == 0) return EndCond; - + if (!EndCond) return nullptr; + // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. Value *CurVar = C.getBuilder().CreateLoad(Alloca, VarName.c_str()); Value *NextVar = C.getBuilder().CreateFAdd(CurVar, StepVal, "nextvar"); C.getBuilder().CreateStore(NextVar, Alloca); - + // Convert condition to a bool by comparing equal to 0.0. - EndCond = C.getBuilder().CreateFCmpONE(EndCond, + EndCond = C.getBuilder().CreateFCmpONE(EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); - + // Create the "after loop" block and insert it. BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - + // Insert the conditional branch into the end of LoopEndBB. C.getBuilder().CreateCondBr(EndCond, LoopBB, AfterBB); - + // Any new code will be inserted in AfterBB. C.getBuilder().SetInsertPoint(AfterBB); - + // Restore the unshadowed variable. if (OldVal) C.NamedValues[VarName] = OldVal; else C.NamedValues.erase(VarName); - // for expr always returns 0.0. return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); } Value *VarExprAST::IRGen(IRGenContext &C) const { std::vector OldBindings; - + Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) { auto &VarName = VarBindings[i].first; auto &Init = VarBindings[i].second; - + // Emit the initializer before adding the variable to scope, this prevents // the initializer from referencing the variable itself, and permits stuff // like this: @@ -1005,22 +1012,22 @@ Value *VarExprAST::IRGen(IRGenContext &C) const { if (!InitVal) return nullptr; } else // If not specified, use 0.0. InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); - + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); C.getBuilder().CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. OldBindings.push_back(C.NamedValues[VarName]); - + // Remember this binding. C.NamedValues[VarName] = Alloca; } - + // Codegen the body, now that all vars are in scope. Value *BodyVal = Body->IRGen(C); if (!BodyVal) return nullptr; - + // Pop all our variables from scope. for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) C.NamedValues[VarBindings[i].first] = OldBindings[i]; @@ -1033,7 +1040,7 @@ Function *PrototypeAST::IRGen(IRGenContext &C) const { std::string FnName = MakeLegalFunctionName(Name); // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), + std::vector Doubles(Args.size(), Type::getDoubleTy(getGlobalContext())); FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); @@ -1046,26 +1053,26 @@ Function *PrototypeAST::IRGen(IRGenContext &C) const { // Delete the one we just made and get the existing one. F->eraseFromParent(); F = C.getM().getFunction(Name); - + // If F already has a body, reject this. if (!F->empty()) { ErrorP("redefinition of function"); return nullptr; } - + // If F took a different number of args, reject. if (F->arg_size() != Args.size()) { ErrorP("redefinition of function with different # args"); return nullptr; } } - + // Set names for all arguments. unsigned Idx = 0; for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); ++AI, ++Idx) AI->setName(Args[Idx]); - + return F; } @@ -1087,19 +1094,19 @@ void PrototypeAST::CreateArgumentAllocas(Function *F, IRGenContext &C) { Function *FunctionAST::IRGen(IRGenContext &C) const { C.NamedValues.clear(); - + Function *TheFunction = Proto->IRGen(C); if (!TheFunction) return nullptr; - + // If this is an operator, install it. if (Proto->isBinaryOp()) BinopPrecedence[Proto->getOperatorName()] = Proto->Precedence; - + // Create a new basic block to start insertion into. BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); C.getBuilder().SetInsertPoint(BB); - + // Add all arguments to the symbol table and create their allocas. Proto->CreateArgumentAllocas(TheFunction, C); @@ -1112,7 +1119,7 @@ Function *FunctionAST::IRGen(IRGenContext &C) const { return TheFunction; } - + // Error reading body, remove function. TheFunction->eraseFromParent(); @@ -1138,6 +1145,12 @@ static std::unique_ptr IRGen(SessionContext &S, return C.takeM(); } +template +static std::vector singletonSet(T t) { + std::vector Vec; + Vec.push_back(std::move(t)); + return Vec; +} static void EarthShatteringKaboom() { fprintf(stderr, "Earth shattering kaboom."); @@ -1149,143 +1162,159 @@ public: typedef ObjectLinkingLayer<> ObjLayerT; typedef IRCompileLayer CompileLayerT; typedef LazyEmittingLayer LazyEmitLayerT; - typedef LazyEmitLayerT::ModuleSetHandleT ModuleHandleT; - std::string Mangle(const std::string &Name) { + KaleidoscopeJIT(SessionContext &Session) + : Session(Session), + CompileLayer(ObjectLayer, SimpleCompiler(Session.getTarget())), + LazyEmitLayer(CompileLayer), + CompileCallbacks(reinterpret_cast(EarthShatteringKaboom)) {} + + std::string mangle(const std::string &Name) { std::string MangledName; { raw_string_ostream MangledNameStream(MangledName); - Mang.getNameWithPrefix(MangledNameStream, Name); + Mangler::getNameWithPrefix(MangledNameStream, Name, + Session.getTarget().createDataLayout()); } return MangledName; } - KaleidoscopeJIT(SessionContext &Session) - : TM(EngineBuilder().selectTarget()), - Mang(TM->getDataLayout()), Session(Session), - ObjectLayer( - [](){ return llvm::make_unique(); }), - CompileLayer(ObjectLayer, SimpleCompiler(*TM)), - LazyEmitLayer(CompileLayer), - CompileCallbacks(LazyEmitLayer, Session.getLLVMContext(), - reinterpret_cast(EarthShatteringKaboom), - 64) {} + void addFunctionAST(std::unique_ptr FnAST) { + std::cerr << "Adding AST: " << FnAST->Proto->Name << "\n"; + FunctionDefs[mangle(FnAST->Proto->Name)] = std::move(FnAST); + } ModuleHandleT addModule(std::unique_ptr M) { - if (!M->getDataLayout()) - M->setDataLayout(TM->getDataLayout()); - - // The LazyEmitLayer takes lists of modules, rather than single modules, so - // we'll just build a single-element list. - std::vector> S; - S.push_back(std::move(M)); - // We need a memory manager to allocate memory and resolve symbols for this - // new module. Create one that resolves symbols by looking back into the JIT. - auto MM = createLookasideRTDyldMM( - [&](const std::string &Name) -> uint64_t { - // First try to find 'Name' within the JIT. - if (auto Symbol = findMangledSymbol(Name)) - return Symbol.getAddress(); - - // If we don't find 'Name' in the JIT, see if we have some AST - // for it. - auto DefI = Session.FunctionDefs.find(Name); - if (DefI == Session.FunctionDefs.end()) - return 0; - - // We have AST for 'Name'. IRGen it, add it to the JIT, and - // return the address for it. - // FIXME: What happens if IRGen fails? - addModule(IRGen(Session, *DefI->second)); - - // Remove the function definition's AST now that we've - // finished with it. - Session.FunctionDefs.erase(DefI); - - return findMangledSymbol(Name).getAddress(); - }, - [](const std::string &S) { return 0; } ); - - return LazyEmitLayer.addModuleSet(std::move(S), std::move(MM)); + // new module. Create one that resolves symbols by looking back into the + // JIT. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + // First try to find 'Name' within the JIT. + if (auto Symbol = findSymbol(Name)) + return RuntimeDyld::SymbolInfo(Symbol.getAddress(), + Symbol.getFlags()); + + // If we don't already have a definition of 'Name' then search + // the ASTs. + return searchFunctionASTs(Name); + }, + [](const std::string &S) { return nullptr; } ); + + return LazyEmitLayer.addModuleSet(singletonSet(std::move(M)), + make_unique(), + std::move(Resolver)); } void removeModule(ModuleHandleT H) { LazyEmitLayer.removeModuleSet(H); } - JITSymbol findMangledSymbol(const std::string &Name) { - return LazyEmitLayer.findSymbol(Name, true); + JITSymbol findSymbol(const std::string &Name) { + return LazyEmitLayer.findSymbol(Name, false); } - JITSymbol findSymbol(const std::string &Name) { - return findMangledSymbol(Mangle(Name)); + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { + return LazyEmitLayer.findSymbolIn(H, Name, false); } - JITSymbol findMangledSymbolIn(LazyEmitLayerT::ModuleSetHandleT H, - const std::string &Name) { - return LazyEmitLayer.findSymbolIn(H, Name, true); + JITSymbol findUnmangledSymbol(const std::string &Name) { + return findSymbol(mangle(Name)); } - JITSymbol findSymbolIn(LazyEmitLayerT::ModuleSetHandleT H, - const std::string &Name) { - return findMangledSymbolIn(H, Mangle(Name)); + JITSymbol findUnmangledSymbolIn(ModuleHandleT H, const std::string &Name) { + return findSymbolIn(H, mangle(Name)); } - void addFunctionDefinition(std::unique_ptr FnAST) { - // Step 1) IRGen a prototype for this function: +private: + + // This method searches the FunctionDefs map for a definition of 'Name'. If it + // finds one it generates a stub for it and returns the address of the stub. + RuntimeDyld::SymbolInfo searchFunctionASTs(const std::string &Name) { + auto DefI = FunctionDefs.find(Name); + if (DefI == FunctionDefs.end()) + return nullptr; + + // Return the address of the stub. + // Take the FunctionAST out of the map. + auto FnAST = std::move(DefI->second); + FunctionDefs.erase(DefI); + + // IRGen the AST, add it to the JIT, and return the address for it. + auto H = irGenStub(std::move(FnAST)); + auto Sym = findSymbolIn(H, Name); + return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); + } + + // This method will take the AST for a function definition and IR-gen a stub + // for that function that will, on first call, IR-gen the actual body of the + // function. + ModuleHandleT irGenStub(std::unique_ptr FnAST) { + // Step 1) IRGen a prototype for the stub. This will have the same type as + // the function. IRGenContext C(Session); Function *F = FnAST->Proto->IRGen(C); - C.getM().setDataLayout(TM->getDataLayout()); - // Step 2) Create a compile callback that will be used to compile this - // function when it is first called. - auto CallbackInfo = - CompileCallbacks.getCompileCallback(*F->getFunctionType()); + // Step 2) Get a compile callback that can be used to compile the body of + // the function. The resulting CallbackInfo type will let us set the + // compile and update actions for the callback, and get a pointer to + // the jit trampoline that we need to call to trigger those actions. + auto CallbackInfo = CompileCallbacks.getCompileCallback(); // Step 3) Create a stub that will indirectly call the body of this // function once it is compiled. Initially, set the function - // pointer for the indirection to point at the compile callback. + // pointer for the indirection to point at the trampoline. std::string BodyPtrName = (F->getName() + "$address").str(); GlobalVariable *FunctionBodyPointer = - createImplPointer(*F, BodyPtrName, CallbackInfo.getAddress()); + createImplPointer(*F->getType(), *F->getParent(), BodyPtrName, + createIRTypedAddress(*F->getFunctionType(), + CallbackInfo.getAddress())); makeStub(*F, *FunctionBodyPointer); // Step 4) Add the module containing the stub to the JIT. - auto H = addModule(C.takeM()); + auto StubH = addModule(C.takeM()); - // Step 5) Set the compile and update actions for the callback. The compile - // action will IRGen and Codegen the function. The update action - // will update FunctionBodyPointer to point at the newly compiled - // function pointer. + // Step 5) Set the compile and update actions. + // + // The compile action will IRGen the function and add it to the JIT, then + // request its address, which will trigger codegen. Since we don't need the + // AST after this, we pass ownership of the AST into the compile action: + // compile actions (and update actions) are deleted after they're run, so + // this will free the AST for us. // - // FIXME: Use generalized capture for FnAST when we get C++14 support. - FunctionAST *FnASTPtr = FnAST.release(); - CallbackInfo.setCompileAction([this,FnASTPtr](){ - std::unique_ptr Fn(FnASTPtr); + // The update action will update FunctionBodyPointer to point at the newly + // compiled function. + std::shared_ptr Fn = std::move(FnAST); + CallbackInfo.setCompileAction([this, Fn, BodyPtrName, StubH]() { auto H = addModule(IRGen(Session, *Fn)); - return findSymbolIn(H, Fn->Proto->Name).getAddress(); + auto BodySym = findUnmangledSymbolIn(H, Fn->Proto->Name); + auto BodyPtrSym = findUnmangledSymbolIn(StubH, BodyPtrName); + assert(BodySym && "Missing function body."); + assert(BodyPtrSym && "Missing function pointer."); + auto BodyAddr = BodySym.getAddress(); + auto BodyPtr = reinterpret_cast( + static_cast(BodyPtrSym.getAddress())); + memcpy(BodyPtr, &BodyAddr, sizeof(uintptr_t)); + return BodyAddr; }); - CallbackInfo.setUpdateAction( - CompileCallbacks.getLocalFPUpdater(H, BodyPtrName)); - } -private: + return StubH; + } - std::unique_ptr TM; - Mangler Mang; SessionContext &Session; - + SectionMemoryManager CCMgrMemMgr; ObjLayerT ObjectLayer; CompileLayerT CompileLayer; LazyEmitLayerT LazyEmitLayer; - JITCompileCallbackManager CompileCallbacks; + std::map> FunctionDefs; + + JITCompileCallbackManager CompileCallbacks; }; static void HandleDefinition(SessionContext &S, KaleidoscopeJIT &J) { if (auto F = ParseDefinition()) { S.addPrototypeAST(llvm::make_unique(*F->Proto)); - J.addFunctionDefinition(std::move(F)); + J.addFunctionAST(std::move(F)); } else { // Skip token for error recovery. getNextToken(); @@ -1315,8 +1344,8 @@ static void HandleTopLevelExpression(SessionContext &S, KaleidoscopeJIT &J) { auto H = J.addModule(C.takeM()); // Get the address of the JIT'd function in memory. - auto ExprSymbol = J.findSymbol("__anon_expr"); - + auto ExprSymbol = J.findUnmangledSymbol("__anon_expr"); + // Cast it to the right type (takes no arguments, returns a double) so we // can call it as a native function. double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); @@ -1359,20 +1388,20 @@ static void MainLoop() { //===----------------------------------------------------------------------===// /// putchard - putchar that takes a double and returns 0. -extern "C" +extern "C" double putchard(double X) { putchar((char)X); return 0; } /// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" +extern "C" double printd(double X) { printf("%f", X); return 0; } -extern "C" +extern "C" double printlf() { printf("\n"); return 0; @@ -1409,4 +1438,3 @@ int main() { return 0; } -