feature/LLVM_IR #6
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))
|
args_(std::move(args))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // 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
|
#ifndef OBELISK_AST_EXPRESSION_AST_H
|
||||||
#define OBELISK_AST_EXPRESSION_AST_H
|
#define OBELISK_AST_EXPRESSION_AST_H
|
||||||
|
|
||||||
|
#include <llvm/IR/Constants.h>
|
||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
class ExpressionAST
|
class ExpressionAST
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ExpressionAST() = default;
|
virtual ~ExpressionAST() = default;
|
||||||
|
virtual llvm::Value *codegen() = 0;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // 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))
|
body_(std::move(body))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Function *codegen();
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
obelisk_ast_sources = files(
|
obelisk_ast_sources = files(
|
||||||
'call_expression_ast.h',
|
'call_expression_ast.cpp',
|
||||||
'expression_ast.h',
|
'error.cpp',
|
||||||
'function_ast.h',
|
'function_ast.cpp',
|
||||||
'number_expression_ast.h',
|
'number_expression_ast.cpp',
|
||||||
'prototype_ast.h',
|
'prototype_ast.cpp',
|
||||||
'variable_expression_ast.h'
|
'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)
|
number_(number)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // 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
|
#ifndef OBELISK_AST_PROTOTYPE_AST_H
|
||||||
#define OBELISK_AST_PROTOTYPE_AST_H
|
#define OBELISK_AST_PROTOTYPE_AST_H
|
||||||
|
|
||||||
|
#include <llvm/IR/Function.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -28,6 +30,8 @@ namespace obelisk
|
|||||||
{
|
{
|
||||||
return name_;
|
return name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Function* codegen();
|
||||||
};
|
};
|
||||||
} //namespace obelisk
|
} //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)
|
name_(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} //namespace obelisk
|
} //namespace obelisk
|
||||||
|
|
||||||
|
@ -13,8 +13,16 @@ obelisk_sources += obelisk_ast_sources
|
|||||||
subdir('models')
|
subdir('models')
|
||||||
obelisk_sources += obelisk_model_sources
|
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',
|
executable('obelisk',
|
||||||
obelisk_sources,
|
obelisk_sources,
|
||||||
dependencies : [sqlite3],
|
dependencies : [sqlite3],
|
||||||
|
cpp_args : cpp_args.split(),
|
||||||
|
link_args : link_args.split(),
|
||||||
install : true
|
install : true
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user