// 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) ErrorV("Unknown variable name"); return V; } 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() { 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 = AstObjects::TheModule->getFunction(std::string("binary") + Op); assert(F && "binary operator not found!"); Value *Ops[2] = { 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; } Value *ForExprAST::codegen() { // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->codegen(); if (StartVal == 0) return 0; // Make the new basic block for the loop header, inserting after current // block. Function *TheFunction = AstObjects::Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = AstObjects::Builder.GetInsertBlock(); 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); // Start the PHI node with an entry for Start. PHINode *Variable = AstObjects::Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, VarName.c_str()); Variable->addIncoming(StartVal, PreheaderBB); // 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. Value *OldVal = AstObjects::NamedValues[VarName]; AstObjects::NamedValues[VarName] = Variable; // 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)); } Value *NextVar = AstObjects::Builder.CreateFAdd(Variable, StepVal, "nextvar"); // Compute the end condition. Value *EndCond = End->codegen(); if (!EndCond) return nullptr; // 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 *LoopEndBB = AstObjects::Builder.GetInsertBlock(); 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); // Add a new entry to the PHI node for the backedge. Variable->addIncoming(NextVar, LoopEndBB); // 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())); } 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()) AstObjects::NamedValues[Arg.getName()] = &Arg; 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; } }