Update compiler
This commit is contained in:
170
src/compiler/compiler.cpp
Normal file
170
src/compiler/compiler.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "compiler.h"
|
||||
#include "../main.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <llvm-c/TargetMachine.h>
|
||||
|
||||
void error(std::string in) {
|
||||
std::cout << "Compiler error:" << in << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
GroundCompiler::GroundCompiler(const std::string& moduleName) {
|
||||
context = std::make_unique<llvm::LLVMContext>();
|
||||
module = std::make_unique<llvm::Module>(moduleName, *context);
|
||||
builder = std::make_unique<llvm::IRBuilder<>>(*context);
|
||||
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
}
|
||||
|
||||
void GroundCompiler::createMainFunction() {
|
||||
llvm::FunctionType* mainType = llvm::FunctionType::get(
|
||||
llvm::Type::getInt32Ty(*context), false
|
||||
);
|
||||
|
||||
currentFunction = llvm::Function::Create(
|
||||
mainType, llvm::Function::ExternalLinkage, "main", module.get()
|
||||
);
|
||||
|
||||
llvm::BasicBlock* entry = llvm::BasicBlock::Create(
|
||||
*context, "entry", currentFunction
|
||||
);
|
||||
builder -> SetInsertPoint(entry);
|
||||
}
|
||||
|
||||
llvm::Function* GroundCompiler::getPrintfFunction() {
|
||||
llvm::Function* printfFunc = module->getFunction("printf");
|
||||
if (!printfFunc) {
|
||||
llvm::FunctionType* printfType = llvm::FunctionType::get(
|
||||
llvm::Type::getInt32Ty(*context),
|
||||
//llvm::Type::getInt8PtrTy(*context),
|
||||
true
|
||||
);
|
||||
printfFunc = llvm::Function::Create(
|
||||
printfType,
|
||||
llvm::Function::ExternalLinkage,
|
||||
"printf",
|
||||
module.get()
|
||||
);
|
||||
}
|
||||
return printfFunc;
|
||||
}
|
||||
|
||||
llvm::AllocaInst* GroundCompiler::createVariable(const std::string& name, llvm::Type* type) {
|
||||
if (namedVals.find(name) != namedVals.end()) {
|
||||
return namedVals[name];
|
||||
}
|
||||
|
||||
llvm::IRBuilder<> tmpBuilder(
|
||||
¤tFunction -> getEntryBlock(),
|
||||
currentFunction -> getEntryBlock().begin()
|
||||
);
|
||||
llvm::AllocaInst* alloca = tmpBuilder.CreateAlloca(type, nullptr, name);
|
||||
namedVals[name] = alloca;
|
||||
return alloca;
|
||||
}
|
||||
|
||||
void GroundCompiler::compileInstruction(const Instruction& inst) {
|
||||
switch (inst.inst) {
|
||||
case Instructions::Set:
|
||||
{
|
||||
if (inst.args.size() < 2) break;
|
||||
|
||||
const Direct& varRef = std::get<Direct>(inst.args[0]);
|
||||
const Literal& value = std::get<Literal>(inst.args[1]);
|
||||
|
||||
llvm::Value* val = nullptr;
|
||||
llvm::Type* type = nullptr;
|
||||
|
||||
if (std::holds_alternative<int>(value.val)) {
|
||||
int intVal = std::get<int>(value.val);
|
||||
val = llvm::ConstantInt::get(*context, llvm::APInt(32, intVal, true));
|
||||
type = llvm::Type::getInt32Ty(*context);
|
||||
} else {
|
||||
error("Unsupported type at present");
|
||||
}
|
||||
|
||||
llvm::AllocaInst* variable = createVariable(varRef.varName, type);
|
||||
builder->CreateStore(val, variable);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("For now, only set instruction is supported in compiler");
|
||||
}
|
||||
}
|
||||
|
||||
void GroundCompiler::createBasicBlocks(const std::vector<Instruction>& instructions) {
|
||||
for (size_t i = 0; i < instructions.size(); i++) {
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(
|
||||
*context, "line_" + std::to_string(i), currentFunction
|
||||
);
|
||||
lineBlocks[i] = bb;
|
||||
}
|
||||
}
|
||||
|
||||
void GroundCompiler::compile(const std::vector<Instruction>& instructions) {
|
||||
createMainFunction();
|
||||
createBasicBlocks(instructions);
|
||||
|
||||
for (const auto& inst : instructions) {
|
||||
compileInstruction(inst);
|
||||
}
|
||||
|
||||
std::string errorStr;
|
||||
llvm::raw_string_ostream errorStream(errorStr);
|
||||
if (llvm::verifyModule(*module, &errorStream)) {
|
||||
error("Module verification error" + errorStr);
|
||||
}
|
||||
}
|
||||
|
||||
bool GroundCompiler::writeObjectFile(const std::string& filename) {
|
||||
char* targetTripleCStr = LLVMGetDefaultTargetTriple();
|
||||
std::string targetTriple(targetTripleCStr);
|
||||
LLVMDisposeErrorMessage(targetTripleCStr);
|
||||
module -> setTargetTriple(targetTriple);
|
||||
std::string error;
|
||||
const llvm::Target* target = llvm::TargetRegistry::lookupTarget(targetTriple, error);
|
||||
|
||||
if (!target) {
|
||||
llvm::errs() << "Target Error: " << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::TargetOptions opt;
|
||||
llvm::TargetMachine* targetMachine = target -> createTargetMachine(
|
||||
targetTriple, "generic", "", opt, llvm::Reloc::PIC_
|
||||
);
|
||||
|
||||
module -> setDataLayout(targetMachine -> createDataLayout());
|
||||
|
||||
std::error_code ec;
|
||||
llvm::raw_fd_ostream dest(filename, ec, llvm::sys::fs::OF_None);
|
||||
|
||||
if (ec) {
|
||||
llvm::errs() << "Couldn't open file, error: " << ec.message();
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::legacy::PassManager pass;
|
||||
if (targetMachine -> addPassesToEmitFile(pass, dest, nullptr, llvm::CodeGenFileType::ObjectFile)) {
|
||||
llvm::errs() << "Target machine cannot emit object file";
|
||||
return false;
|
||||
}
|
||||
|
||||
pass.run(*module);
|
||||
dest.flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroundCompiler::printIR() {
|
||||
module->print(llvm::outs(), nullptr);
|
||||
}
|
||||
|
||||
void compile(std::vector<Instruction> instructions) {
|
||||
std::cout << "gonna compile some crap" << std::endl;
|
||||
GroundCompiler compiler("cool_program");
|
||||
compiler.compile(instructions);
|
||||
compiler.printIR();
|
||||
}
|
||||
47
src/compiler/compiler.h
Normal file
47
src/compiler/compiler.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Verifier.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/MC/TargetRegistry.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
//#include <llvm/Support/Host.h>
|
||||
#include "../main.h"
|
||||
|
||||
void error(std::string in);
|
||||
|
||||
// class to make llvming around easier
|
||||
class GroundCompiler {
|
||||
private:
|
||||
std::unique_ptr<llvm::LLVMContext> context;
|
||||
std::unique_ptr<llvm::Module> module;
|
||||
std::unique_ptr<llvm::IRBuilder<>> builder;
|
||||
|
||||
std::map<std::string, llvm::AllocaInst*> namedVals;
|
||||
|
||||
llvm::Function* currentFunction;
|
||||
|
||||
std::map<int, llvm::BasicBlock*> lineBlocks;
|
||||
public:
|
||||
GroundCompiler(const std::string& moduleName);
|
||||
void createMainFunction();
|
||||
llvm::Function* getPrintfFunction();
|
||||
llvm::AllocaInst* createVariable(const std::string& name, llvm::Type* type);
|
||||
void compileInstruction(const Instruction& inst);
|
||||
void createBasicBlocks(const std::vector<Instruction>& instructions);
|
||||
void compile(const std::vector<Instruction>& instructions);
|
||||
bool writeObjectFile(const std::string& filename);
|
||||
void printIR();
|
||||
};
|
||||
|
||||
void compile(std::vector<Instruction> instructions);
|
||||
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -38,6 +38,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "main.h"
|
||||
#include "data/data.h"
|
||||
@@ -45,6 +46,7 @@
|
||||
#include "lexer/lexer.h"
|
||||
#include "parser/parser.h"
|
||||
#include "interpreter/interpreter.h"
|
||||
#include "compiler/compiler.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -58,9 +60,15 @@ int main(int argc, char* argv[]) {
|
||||
cout << "Usage: ground <file>" << endl;
|
||||
return 1;
|
||||
}
|
||||
ifstream f(argv[1]);
|
||||
int fileArg = 1;
|
||||
bool compiling = false;
|
||||
if (strcmp(argv[1], "-c") == 0 || strcmp(argv[1], "--compile") == 0) {
|
||||
fileArg++;
|
||||
compiling = true;
|
||||
}
|
||||
ifstream f(argv[fileArg]);
|
||||
if (!f) {
|
||||
cout << "Could not open file " << argv[1] << endl;
|
||||
cout << "Could not open file " << argv[fileArg] << endl;
|
||||
return 1;
|
||||
}
|
||||
string file_contents((istreambuf_iterator<char>(f)), istreambuf_iterator<char>());
|
||||
@@ -68,8 +76,12 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
vector<vector<string>> lexed = lexer(file_contents);
|
||||
vector<Instruction> parsed = parser(lexed);
|
||||
preProcessLabels(parsed);
|
||||
exec(parsed);
|
||||
if (compiling) {
|
||||
compile(parsed);
|
||||
} else {
|
||||
preProcessLabels(parsed);
|
||||
exec(parsed);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user