add IR code generation to the AST
This commit is contained in:
parent
43f8f292ff
commit
71156924c6
20
src/ast/ast.h
Normal file
20
src/ast/ast.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef OBELISK_AST_AST_H
|
||||
#define OBELISK_AST_AST_H
|
||||
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace obelisk
|
||||
{
|
||||
static std::unique_ptr<llvm::LLVMContext> TheContext;
|
||||
static std::unique_ptr<llvm::Module> TheModule;
|
||||
static std::unique_ptr<llvm::IRBuilder<>> Builder;
|
||||
static std::map<std::string, llvm::Value *> NamedValues;
|
||||
} // namespace obelisk
|
||||
|
||||
#endif
|
31
src/ast/call_expression_ast.cpp
Normal file
31
src/ast/call_expression_ast.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "ast/ast.h"
|
||||
#include "ast/call_expression_ast.h"
|
||||
#include "ast/error.h"
|
||||
|
||||
llvm::Value *obelisk::CallExpressionAST::codegen()
|
||||
{
|
||||
// Look up the name in the global module table.
|
||||
llvm::Function *calleeF = TheModule->getFunction(callee_);
|
||||
if (!calleeF)
|
||||
{
|
||||
return LogErrorV("Unknown function referenced");
|
||||
}
|
||||
|
||||
// If argument mismatch error.
|
||||
if (calleeF->arg_size() != args_.size())
|
||||
{
|
||||
return LogErrorV("Incorrect # arguments passed");
|
||||
}
|
||||
|
||||
std::vector<llvm::Value *> argsV;
|
||||
for (unsigned 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");
|
||||
}
|
@ -28,6 +28,8 @@ namespace obelisk
|
||||
args_(std::move(args))
|
||||
{
|
||||
}
|
||||
|
||||
llvm::Value *codegen() override;
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
13
src/ast/error.cpp
Normal file
13
src/ast/error.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "ast/error.h"
|
||||
|
||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::LogError(const char *Str)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", Str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::Value *obelisk::LogErrorV(const char *Str)
|
||||
{
|
||||
LogError(Str);
|
||||
return nullptr;
|
||||
}
|
14
src/ast/error.h
Normal file
14
src/ast/error.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef OBELISK_AST_ERROR_H
|
||||
#define OBELISK_AST_ERROR_H
|
||||
|
||||
#include "ast/expression_ast.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace obelisk
|
||||
{
|
||||
std::unique_ptr<ExpressionAST> LogError(const char *Str);
|
||||
llvm::Value *LogErrorV(const char *Str);
|
||||
} // namespace obelisk
|
||||
|
||||
#endif
|
@ -1,12 +1,15 @@
|
||||
#ifndef OBELISK_AST_EXPRESSION_AST_H
|
||||
#define OBELISK_AST_EXPRESSION_AST_H
|
||||
|
||||
#include <llvm/IR/Constants.h>
|
||||
|
||||
namespace obelisk
|
||||
{
|
||||
class ExpressionAST
|
||||
{
|
||||
public:
|
||||
virtual ~ExpressionAST() = default;
|
||||
virtual llvm::Value *codegen() = 0;
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
39
src/ast/function_ast.cpp
Normal file
39
src/ast/function_ast.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ast/ast.h"
|
||||
#include "ast/function_ast.h"
|
||||
|
||||
#include <llvm/IR/Verifier.h>
|
||||
|
||||
llvm::Function *obelisk::FunctionAST::codegen()
|
||||
{
|
||||
llvm::Function *theFunction = TheModule->getFunction(prototype_->getName());
|
||||
|
||||
if (!theFunction)
|
||||
{
|
||||
theFunction = prototype_->codegen();
|
||||
}
|
||||
|
||||
if (!theFunction)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::BasicBlock *bB
|
||||
= llvm::BasicBlock::Create(*TheContext, "entry", theFunction);
|
||||
Builder->SetInsertPoint(bB);
|
||||
|
||||
NamedValues.clear();
|
||||
for (auto &arg : theFunction->args())
|
||||
{
|
||||
NamedValues[std::string(arg.getName())] = &arg;
|
||||
}
|
||||
|
||||
if (llvm::Value *retVal = body_->codegen())
|
||||
{
|
||||
Builder->CreateRet(retVal);
|
||||
llvm::verifyFunction(*theFunction);
|
||||
return theFunction;
|
||||
}
|
||||
|
||||
theFunction->eraseFromParent();
|
||||
return nullptr;
|
||||
}
|
@ -24,6 +24,8 @@ namespace obelisk
|
||||
body_(std::move(body))
|
||||
{
|
||||
}
|
||||
|
||||
llvm::Function *codegen();
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
obelisk_ast_sources = files(
|
||||
'call_expression_ast.h',
|
||||
'expression_ast.h',
|
||||
'function_ast.h',
|
||||
'number_expression_ast.h',
|
||||
'prototype_ast.h',
|
||||
'variable_expression_ast.h'
|
||||
'call_expression_ast.cpp',
|
||||
'error.cpp',
|
||||
'function_ast.cpp',
|
||||
'number_expression_ast.cpp',
|
||||
'prototype_ast.cpp',
|
||||
'variable_expression_ast.cpp'
|
||||
)
|
||||
|
7
src/ast/number_expression_ast.cpp
Normal file
7
src/ast/number_expression_ast.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "ast/ast.h"
|
||||
#include "ast/number_expression_ast.h"
|
||||
|
||||
llvm::Value *obelisk::NumberExpressionAST::codegen()
|
||||
{
|
||||
return llvm::ConstantFP::get(*TheContext, llvm::APFloat(number_));
|
||||
}
|
@ -18,6 +18,8 @@ namespace obelisk
|
||||
number_(number)
|
||||
{
|
||||
}
|
||||
|
||||
llvm::Value *codegen() override;
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
25
src/ast/prototype_ast.cpp
Normal file
25
src/ast/prototype_ast.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "ast/ast.h"
|
||||
#include "ast/prototype_ast.h"
|
||||
|
||||
llvm::Function *obelisk::PrototypeAST::codegen()
|
||||
{
|
||||
std::vector<llvm::Type *> doubles(args_.size(),
|
||||
llvm::Type::getDoubleTy(*TheContext));
|
||||
llvm::FunctionType *FT
|
||||
= llvm::FunctionType::get(llvm::Type::getDoubleTy(*TheContext),
|
||||
doubles,
|
||||
false);
|
||||
|
||||
llvm::Function *F = llvm::Function::Create(FT,
|
||||
llvm::Function::ExternalLinkage,
|
||||
name_,
|
||||
obelisk::TheModule.get());
|
||||
|
||||
unsigned idx = 0;
|
||||
for (auto &arg : F->args())
|
||||
{
|
||||
arg.setName(args_[idx++]);
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#ifndef OBELISK_AST_PROTOTYPE_AST_H
|
||||
#define OBELISK_AST_PROTOTYPE_AST_H
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -28,6 +30,8 @@ namespace obelisk
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
llvm::Function* codegen();
|
||||
};
|
||||
} //namespace obelisk
|
||||
|
||||
|
13
src/ast/variable_expression_ast.cpp
Normal file
13
src/ast/variable_expression_ast.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "ast/ast.h"
|
||||
#include "ast/error.h"
|
||||
#include "ast/variable_expression_ast.h"
|
||||
|
||||
llvm::Value *obelisk::VariableExpressionAST::codegen()
|
||||
{
|
||||
llvm::Value *V = NamedValues[name_];
|
||||
if (!V)
|
||||
{
|
||||
return obelisk::LogErrorV("Unknown variable name");
|
||||
}
|
||||
return V;
|
||||
}
|
@ -19,6 +19,8 @@ namespace obelisk
|
||||
name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
llvm::Value *codegen() override;
|
||||
};
|
||||
} //namespace obelisk
|
||||
|
||||
|
@ -13,8 +13,16 @@ obelisk_sources += obelisk_ast_sources
|
||||
subdir('models')
|
||||
obelisk_sources += obelisk_model_sources
|
||||
|
||||
r = run_command('llvm-config', '--cppflags', check : true)
|
||||
cpp_args = ' ' + r.stdout().replace('\n', ' ').replace('-I', '-isystem')
|
||||
|
||||
r = run_command('llvm-config', '--ldflags', '--system-libs', '--libs', 'core', check : true)
|
||||
link_args = ' ' + r.stdout().replace('\n', ' ')
|
||||
|
||||
executable('obelisk',
|
||||
obelisk_sources,
|
||||
dependencies : [sqlite3],
|
||||
cpp_args : cpp_args.split(),
|
||||
link_args : link_args.split(),
|
||||
install : true
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user