X-Git-Url: http://git.lukelau.me/?p=kaleidoscope.git;a=blobdiff_plain;f=Kaleidoscope%2Fcodegen.cpp;fp=Kaleidoscope%2Fcodegen.cpp;h=c185a3e0c699f4445a0435c494953c13c8a19343;hp=0000000000000000000000000000000000000000;hb=5f81038886345b9c1e130bc7cfdd463e76b37b84;hpb=400fd8ffcac74658d4323ba0b6f3519204075baa diff --git a/Kaleidoscope/codegen.cpp b/Kaleidoscope/codegen.cpp new file mode 100644 index 0000000..c185a3e --- /dev/null +++ b/Kaleidoscope/codegen.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/Reassociate.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include +#include +#include +#include +#include +#include +#include +#include "ast.hpp" +#include "codegen.hpp" +#include "shared.h" + +using namespace llvm; + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static AnalysisManager TheAM; +static std::map NamedValues; +static std::unique_ptr TheFPM; +static std::unique_ptr TheFAM; + +void InitializeModuleAndPassManager(void) { + TheModule = llvm::make_unique("Kaleidoscope jit", TheContext); + + TheFPM = make_unique(); + TheFAM = make_unique(); + + PassBuilder PB; + PB.registerFunctionAnalyses(*TheFAM); + + TheFPM->addPass(InstCombinePass()); + TheFPM->addPass(ReassociatePass()); + TheFPM->addPass(SimplifyCFGPass()); + TheFPM->addPass(GVNHoistPass()); + TheFPM->addPass(GVNSinkPass()); +} + +void PrintModule() { + TheModule->print(errs(), nullptr); +} + +std::map> functionProtos; + +Function *getFunction(std::string name) { + if (auto *func = TheModule->getFunction(name)) + return func; + + auto iterator = functionProtos.find(name); + if (iterator != functionProtos.end()) + return iterator->second->codegen(); + + return nullptr; +} + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + Value *V = NamedValues[Name]; + if (!V) + LogErrorV("Unknown variable name"); + return V; +} + +Value *BinaryExprAST::codegen() { + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + + if (!L || !R) return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // convert bool 0/1 to double 0.0/1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + return LogErrorV("Invalid binary operator"); + } +} + +Value *CallExprAST::codegen() { + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect number of arguments passed"); + + std::vector ArgsV; + for (unsigned long i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Function *PrototypeAST::codegen() { + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + + FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + Function *func = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + unsigned i = 0; + for (auto &arg : func->args()) + arg.setName(Args[i++]); + + return func; +} + +Function *FunctionAST::codegen() { + //Transfer ownership but keep a reference + auto &P = *Prototype; + functionProtos[Prototype->getName()] = std::move(Prototype); + + Function *func = getFunction(P.getName()); + + if (!func) return nullptr; + + BasicBlock *bb = BasicBlock::Create(TheContext, "entry", func); + Builder.SetInsertPoint(bb); + + NamedValues.clear(); + for (auto &arg: func->args()) + NamedValues[arg.getName()] = &arg; + + if (Value *retVal = Body->codegen()) { + Builder.CreateRet(retVal); + verifyFunction(*func); + TheFPM->run(*func, *TheFAM); + return func; + } + + func->eraseFromParent(); + return nullptr; +}