123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- // 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<Module> AstObjects::TheModule =
- std::make_unique<Module>("my cool jit", getGlobalContext());
- IRBuilder<> AstObjects::Builder(getGlobalContext());
- std::map<std::string, AllocaInst*> 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<VariableExprAST *>(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<Value *> 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<AllocaInst *> 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<Type *> 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;
- }
- }*/
- }
|