2023-09-27 18:18:05 +00:00
|
|
|
#include "Compiler.hpp"
|
2023-09-27 21:05:04 +00:00
|
|
|
#include <llvm/IR/BasicBlock.h>
|
|
|
|
#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()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ Compiler::~Compiler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-09-27 21:05:04 +00:00
|
|
|
void Compiler::gen()
|
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);
|
|
|
|
|
|
|
|
auto filename = "output.o";
|
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
|
|
|
pass.run(*m_module);
|
|
|
|
dest.flush();
|
|
|
|
|
|
|
|
m_module->print(llvm::outs(), nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Value* Compiler::compile(std::shared_ptr<Node> node)
|
|
|
|
{
|
|
|
|
switch (node->type())
|
|
|
|
{
|
|
|
|
case NODE_PROG: {
|
|
|
|
auto* block = llvm::BasicBlock::Create(*m_context,
|
|
|
|
"entry");
|
|
|
|
m_builder->SetInsertPoint(block);
|
|
|
|
|
|
|
|
for (size_t i=0; i<node->size(); i++)
|
|
|
|
{
|
|
|
|
compile(node->child(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return block;
|
|
|
|
} 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: {
|
|
|
|
return llvm::ConstantInt::get(*m_context, llvm::APInt(32, 0, true));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
WG_ASSERT(false,
|
|
|
|
std::string()
|
|
|
|
+ "cannot compile unknown node '"
|
|
|
|
+ NodeTypeStr[node->type()]
|
|
|
|
+ "'");
|
|
|
|
}
|
2023-09-27 18:18:05 +00:00
|
|
|
}
|
|
|
|
}
|