2023-09-27 18:18:05 +00:00
|
|
|
#include "Compiler.hpp"
|
2023-09-29 09:01:46 +00:00
|
|
|
#include <llvm/Support/DynamicLibrary.h>
|
2023-09-27 21:05:04 +00:00
|
|
|
#include <llvm/IR/BasicBlock.h>
|
2023-09-28 19:37:10 +00:00
|
|
|
#include <llvm/IR/Verifier.h>
|
|
|
|
#include <llvm/IR/Type.h>
|
2023-09-27 21:05:04 +00:00
|
|
|
#include <llvm/TargetParser/Host.h>
|
|
|
|
#include <llvm/Target/TargetOptions.h>
|
|
|
|
#include <llvm/Target/TargetMachine.h>
|
|
|
|
#include <llvm/Support/TargetSelect.h>
|
|
|
|
#include <llvm/Support/FileSystem.h>
|
|
|
|
#include <llvm/MC/TargetRegistry.h>
|
|
|
|
#include <llvm/IR/LegacyPassManager.h>
|
2023-09-27 18:18:05 +00:00
|
|
|
|
|
|
|
namespace wg
|
|
|
|
{
|
|
|
|
/*explicit*/ Compiler::Compiler()
|
|
|
|
{
|
2023-09-28 19:37:10 +00:00
|
|
|
|
2023-09-27 18:18:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ Compiler::~Compiler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-09-28 20:18:03 +00:00
|
|
|
void Compiler::gen(std::filesystem::path obj)
|
2023-09-27 18:18:05 +00:00
|
|
|
{
|
2023-09-27 21:05:04 +00:00
|
|
|
auto target_triple = llvm::sys::getDefaultTargetTriple();
|
|
|
|
llvm::InitializeAllTargetInfos();
|
|
|
|
llvm::InitializeAllTargets();
|
|
|
|
llvm::InitializeAllTargetMCs();
|
|
|
|
llvm::InitializeAllAsmParsers();
|
|
|
|
llvm::InitializeAllAsmPrinters();
|
|
|
|
|
|
|
|
std::string err;
|
|
|
|
auto target = llvm::TargetRegistry::lookupTarget(target_triple, err);
|
|
|
|
|
|
|
|
if (!target)
|
|
|
|
{
|
|
|
|
llvm::errs() << err;
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto cpu = "generic";
|
|
|
|
auto features = "";
|
|
|
|
|
|
|
|
llvm::TargetOptions opt;
|
|
|
|
auto rm = std::optional<llvm::Reloc::Model>();
|
|
|
|
auto target_machine = target->createTargetMachine(target_triple,
|
|
|
|
cpu,
|
|
|
|
features,
|
|
|
|
opt,
|
|
|
|
rm);
|
|
|
|
|
|
|
|
m_module->setDataLayout(target_machine->createDataLayout());
|
|
|
|
m_module->setTargetTriple(target_triple);
|
|
|
|
|
2023-09-28 20:18:03 +00:00
|
|
|
auto filename = obj.string();
|
2023-09-27 21:05:04 +00:00
|
|
|
std::error_code ec;
|
|
|
|
|
|
|
|
llvm::raw_fd_ostream dest(filename, ec, llvm::sys::fs::OF_None);
|
|
|
|
WG_ASSERT(!ec, "cannot write output file.");
|
|
|
|
|
|
|
|
llvm::legacy::PassManager pass;
|
|
|
|
auto file_type = llvm::CodeGenFileType::CGFT_ObjectFile;
|
|
|
|
|
|
|
|
if (target_machine->addPassesToEmitFile(pass, dest, nullptr, file_type))
|
|
|
|
{
|
|
|
|
llvm::errs() << "Target machine cannot emit a file of this type";
|
|
|
|
}
|
|
|
|
|
2023-09-28 19:37:10 +00:00
|
|
|
llvm::verifyModule(*m_module);
|
2023-09-29 09:01:46 +00:00
|
|
|
|
2023-09-27 21:05:04 +00:00
|
|
|
pass.run(*m_module);
|
2023-09-28 19:37:10 +00:00
|
|
|
|
2023-09-27 21:05:04 +00:00
|
|
|
dest.flush();
|
|
|
|
}
|
|
|
|
|
2023-09-29 09:01:46 +00:00
|
|
|
void Compiler::init_package(std::shared_ptr<Node> node)
|
|
|
|
{
|
|
|
|
m_pkg->scan(node, *m_sym);
|
|
|
|
}
|
|
|
|
|
2023-09-27 21:05:04 +00:00
|
|
|
llvm::Value* Compiler::compile(std::shared_ptr<Node> node)
|
|
|
|
{
|
|
|
|
switch (node->type())
|
|
|
|
{
|
|
|
|
case NODE_PROG: {
|
2023-09-28 19:37:10 +00:00
|
|
|
for (size_t i=0; i<node->size(); i++)
|
|
|
|
{
|
|
|
|
compile(node->child(i));
|
|
|
|
}
|
2023-09-27 21:05:04 +00:00
|
|
|
|
2023-09-28 19:37:10 +00:00
|
|
|
return nullptr;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_BLOCK: {
|
2023-09-27 21:05:04 +00:00
|
|
|
for (size_t i=0; i<node->size(); i++)
|
|
|
|
{
|
|
|
|
compile(node->child(i));
|
|
|
|
}
|
2023-09-28 19:37:10 +00:00
|
|
|
return nullptr;
|
|
|
|
} break;
|
|
|
|
|
2023-09-29 09:01:46 +00:00
|
|
|
case NODE_DIR: {
|
|
|
|
if (node->child(0)->repr() == "import")
|
|
|
|
{
|
|
|
|
std::string pkg_name = node->child(1)->repr();
|
|
|
|
std::cout << "-> " << pkg_name << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
} break;
|
|
|
|
|
2023-09-28 19:37:10 +00:00
|
|
|
case NODE_RETURN: {
|
|
|
|
return m_builder->CreateRet(compile(node->child(0)));
|
|
|
|
} break;
|
|
|
|
|
2023-09-29 09:01:46 +00:00
|
|
|
/*case NODE_EXTERN: {
|
2023-09-28 19:37:10 +00:00
|
|
|
auto ident = node->child(0)->repr();
|
|
|
|
auto params = node->child(1);
|
|
|
|
auto ret = node->child(2);
|
|
|
|
|
|
|
|
std::vector<std::string> names;
|
|
|
|
std::vector<llvm::Type*> types;
|
|
|
|
|
|
|
|
for (size_t i=0; i<params->size(); i++)
|
|
|
|
{
|
|
|
|
auto param = params->child(i);
|
|
|
|
|
|
|
|
if (param->type() == NODE_IDENT)
|
|
|
|
{
|
|
|
|
names.push_back(param->repr());
|
|
|
|
}
|
|
|
|
else if (param->type() == NODE_TYPE)
|
|
|
|
{
|
|
|
|
auto ty = llvm::Type::getInt32Ty(*m_context);
|
|
|
|
|
|
|
|
for (auto name: names)
|
|
|
|
{
|
|
|
|
m_sym->declare(name, ty, node->loc());
|
|
|
|
types.push_back(ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
names.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Type* ret_type = llvm::Type::getVoidTy(*m_context);
|
|
|
|
|
|
|
|
if (ret->size() > 0)
|
|
|
|
{
|
|
|
|
ret_type = llvm::Type::getInt32Ty(*m_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto fun_type = llvm::FunctionType::get(ret_type, types, false);
|
|
|
|
auto fun = llvm::Function::Create(fun_type,
|
|
|
|
llvm::Function::ExternalLinkage,
|
|
|
|
ident,
|
|
|
|
*m_module);
|
2023-09-27 21:05:04 +00:00
|
|
|
|
2023-09-28 19:37:10 +00:00
|
|
|
m_sym->declare_prototype(ident, fun_type, node->loc());
|
|
|
|
return fun;
|
2023-09-29 09:01:46 +00:00
|
|
|
} break;*/
|
2023-09-28 19:37:10 +00:00
|
|
|
|
|
|
|
case NODE_FUNDECL: {
|
|
|
|
auto ident = node->child(0)->repr();
|
|
|
|
auto body = node->child(3);
|
2023-09-29 09:01:46 +00:00
|
|
|
auto fun = m_module-> getFunction(ident);
|
2023-09-28 19:37:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
llvm::BasicBlock* old_bb = m_builder->GetInsertBlock();
|
|
|
|
|
|
|
|
auto* bb = llvm::BasicBlock::Create(*m_context,
|
|
|
|
"entry",
|
|
|
|
fun);
|
|
|
|
m_builder->SetInsertPoint(bb);
|
|
|
|
|
|
|
|
compile(body);
|
|
|
|
|
|
|
|
m_builder->SetInsertPoint(old_bb);
|
|
|
|
|
|
|
|
llvm::verifyFunction(*fun);
|
|
|
|
|
|
|
|
return fun;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_CALL: {
|
|
|
|
std::string ident = node->child(0)->repr();
|
|
|
|
|
|
|
|
auto fun = m_module->getFunction(ident);
|
|
|
|
WG_ASSERT(fun, "cannot call unknown function '" + ident + "'");
|
|
|
|
|
|
|
|
std::vector<llvm::Value*> values;
|
|
|
|
|
|
|
|
for (size_t i=0; i<node->child(1)->size(); i++)
|
|
|
|
{
|
|
|
|
auto arg = node->child(1)->child(i);
|
|
|
|
auto val = compile(arg);
|
|
|
|
values.push_back(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_builder->CreateCall(fun, values);
|
2023-09-27 21:05:04 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_ADD: {
|
|
|
|
auto* lhs = compile(node->child(0));
|
|
|
|
auto* rhs = compile(node->child(1));
|
|
|
|
return m_builder->CreateAdd(lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_SUB: {
|
|
|
|
auto* lhs = compile(node->child(0));
|
|
|
|
auto* rhs = compile(node->child(1));
|
|
|
|
return m_builder->CreateSub(lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_MUL: {
|
|
|
|
auto* lhs = compile(node->child(0));
|
|
|
|
auto* rhs = compile(node->child(1));
|
|
|
|
return m_builder->CreateMul(lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_DIV: {
|
|
|
|
auto* lhs = compile(node->child(0));
|
|
|
|
auto* rhs = compile(node->child(1));
|
|
|
|
return m_builder->CreateSDiv(lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_MOD: {
|
|
|
|
auto* lhs = compile(node->child(0));
|
|
|
|
auto* rhs = compile(node->child(1));
|
|
|
|
return m_builder->CreateSRem(lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_INT: {
|
2023-09-28 19:37:10 +00:00
|
|
|
|
|
|
|
return llvm::ConstantInt::get(*m_context,
|
|
|
|
llvm::APInt(32,
|
|
|
|
std::stoi(node->repr()),
|
|
|
|
true));
|
2023-09-27 21:05:04 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
WG_ASSERT(false,
|
|
|
|
std::string()
|
|
|
|
+ "cannot compile unknown node '"
|
|
|
|
+ NodeTypeStr[node->type()]
|
|
|
|
+ "'");
|
|
|
|
}
|
2023-09-27 18:18:05 +00:00
|
|
|
}
|
|
|
|
}
|