// LLVM includes #include "llvm/IR/Verifier.h" // Local includes #include "Ast.h" #include "Parser.h" #include "JIT.h" using namespace jit; namespace ast{ // attributes added from chapter 3 of the tutorial std::unique_ptr AstObjects::TheModule = std::make_unique("my cool jit", getGlobalContext()); IRBuilder<> AstObjects::Builder(getGlobalContext()); std::map AstObjects::NamedValues; Value *ErrorV(const char *Str) { parser::Error(Str); return nullptr; } Value *NumberExprAST::codegen() { return ConstantFP::get(getGlobalContext(), APFloat(Val)); } Value *VariableExprAST::codegen() { // Look this variable up in the function. Value *V = AstObjects::NamedValues[Name]; if (!V) return ErrorV("Unknown variable name"); // Load the value. return AstObjects::Builder.CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { Value *OperandV = Operand->codegen(); if (!OperandV) return nullptr; Function *F = getFunction(std::string("unary") + Opcode); if (!F) return ErrorV("Unknown unary operator"); return AstObjects::Builder.CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { // Special case '=' because we don't want to emit the LHS as an expression. if (Op == '=') { // Assignment requires the LHS to be an identifier. // This assume we're building without RTTI because LLVM builds that way by // default. If you build LLVM with RTTI this can be changed to a // dynamic_cast for automatic error checking. VariableExprAST *LHSE = static_cast(LHS.get()); if (!LHSE) return ErrorV("destination of '=' must be a variable"); // Codegen the RHS. Value *Val = RHS->codegen(); if (!Val) return nullptr; // Look up the name. Value *Variable = AstObjects::NamedValues[LHSE->getName()]; if (!Variable) return ErrorV("Unknown variable name"); AstObjects::Builder.CreateStore(Val, Variable); return Val; } Value *L = LHS->codegen(); Value *R = RHS->codegen(); if (!L || !R) return nullptr; switch (Op) { case '+': return AstObjects::Builder.CreateFAdd(L, R, "addtmp"); case '-': return AstObjects::Builder.CreateFSub(L, R, "subtmp"); case '*': return AstObjects::Builder.CreateFMul(L, R, "multmp"); case '<': L = AstObjects::Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 return AstObjects::Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), "booltmp"); default: break; } // If it wasn't a builtin binary operator, it must be a user defined one. Emit // a call to it. Function *F = getFunction(std::string("binary") + Op); assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; return AstObjects::Builder.CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { // Look up the name in the global module table. Function *CalleeF = getFunction(Callee); if (!CalleeF) return ErrorV("Unknown function referenced"); // If argument mismatch error. if (CalleeF->arg_size() != Args.size()) return ErrorV("Incorrect # arguments passed"); std::vector ArgsV; for (unsigned i = 0, e = Args.size(); i != e; ++i) { ArgsV.push_back(Args[i]->codegen()); if (!ArgsV.back()) return nullptr; } return AstObjects::Builder.CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { Value *CondV = Cond->codegen(); if (!CondV) return nullptr; // Convert condition to a bool by comparing equal to 0.0. CondV = AstObjects::Builder.CreateFCmpONE( CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); Function *TheFunction = AstObjects::Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); AstObjects::Builder.CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. AstObjects::Builder.SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; AstObjects::Builder.CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. ThenBB = AstObjects::Builder.GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); AstObjects::Builder.SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; AstObjects::Builder.CreateBr(MergeBB); // codegen of 'Else' can change the current block, update ElseBB for the PHI. ElseBB = AstObjects::Builder.GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); AstObjects::Builder.SetInsertPoint(MergeBB); PHINode *PN = AstObjects::Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; } // Output for-loop as: // var = alloca double // ... // start = startexpr // store start -> var // goto loop // loop: // ... // bodyexpr // ... // loopend: // step = stepexpr // endcond = endexpr // // curvar = load var // nextvar = curvar + step // store nextvar -> var // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { Function *TheFunction = AstObjects::Builder.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->codegen(); if (!StartVal) return nullptr; // Store the value into the alloca. AstObjects::Builder.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. AstObjects::Builder.CreateBr(LoopBB); // Start insertion in LoopBB. AstObjects::Builder.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 = AstObjects::NamedValues[VarName]; AstObjects::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->codegen()) return nullptr; // Emit the step value. Value *StepVal = nullptr; if (Step) { StepVal = Step->codegen(); if (!StepVal) return nullptr; } else { // If not specified, use 1.0. StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); } // Compute the end condition. Value *EndCond = End->codegen(); 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 = AstObjects::Builder.CreateLoad(Alloca, VarName.c_str()); Value *NextVar = AstObjects::Builder.CreateFAdd(CurVar, StepVal, "nextvar"); AstObjects::Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. EndCond = AstObjects::Builder.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. AstObjects::Builder.CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. AstObjects::Builder.SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) AstObjects::NamedValues[VarName] = OldVal; else AstObjects::NamedValues.erase(VarName); // for expr always returns 0.0. return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); } Value *VarExprAST::codegen() { std::vector OldBindings; Function *TheFunction = AstObjects::Builder.GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { const std::string &VarName = VarNames[i].first; ExprAST *Init = VarNames[i].second.get(); // Emit the initializer before adding the variable to scope, this prevents // the initializer from referencing the variable itself, and permits stuff // like this: // var a = 1 in // var a = a in ... # refers to outer 'a'. Value *InitVal; if (Init) { InitVal = Init->codegen(); if (!InitVal) return nullptr; } else { // If not specified, use 0.0. InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); AstObjects::Builder.CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. OldBindings.push_back(AstObjects::NamedValues[VarName]); // Remember this binding. AstObjects::NamedValues[VarName] = Alloca; } // Codegen the body, now that all vars are in scope. Value *BodyVal = Body->codegen(); if (!BodyVal) return nullptr; // Pop all our variables from scope. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) AstObjects::NamedValues[VarNames[i].first] = OldBindings[i]; // Return the body computation. return BodyVal; } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. std::vector Doubles(Args.size(), Type::getDoubleTy(getGlobalContext())); FunctionType *FT = FunctionType::get(Type::getDoubleTy( getGlobalContext()), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, AstObjects::TheModule.get()); // Set names for all arguments. unsigned Idx = 0; for (auto &Arg : F->args()) Arg.setName(Args[Idx++]); return F; } Function *FunctionAST::codegen() { // Transfer ownership of the prototype to the FunctionProtos map, but keep a // reference to it for use below. auto &P = *Proto; JITObjects::FunctionProtos[Proto->getName()] = std::move(Proto); Function *TheFunction = getFunction(P.getName()); if (!TheFunction) return nullptr; // If this is an operator, install it. if (P.isBinaryOp()) parser::BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); AstObjects::Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. AstObjects::NamedValues.clear(); for (auto &Arg : TheFunction->args()) { // Create an alloca for this variable. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. AstObjects::Builder.CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. AstObjects::NamedValues[Arg.getName()] = Alloca; } if (Value *RetVal = Body->codegen()) { // Finish off the function. AstObjects::Builder.CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); // Run the optimizer on the function. JITObjects::TheFPM->run(*TheFunction); return TheFunction; } // Error reading body, remove function. TheFunction->eraseFromParent(); if (P.isBinaryOp()) parser::BinopPrecedence.erase(Proto->getOperatorName()); return nullptr; } /// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of /// the function. This is used for mutable variables etc. static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, VarName.c_str()); } /* /// 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) { // Create an alloca for this variable. AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); // Store the initial value into the alloca. AstObjects::Builder.CreateStore(AI, Alloca); // Add arguments to variable symbol table. AstObjects::NamedValues[Args[Idx]] = Alloca; } }*/ }