Update compiler

This commit is contained in:
2026-01-21 11:38:06 +11:00
parent e5a39f07fb
commit 0796bee066
3 changed files with 234 additions and 5 deletions

170
src/compiler/compiler.cpp Normal file
View 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(
&currentFunction -> 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
View 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);

View File

@@ -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;
}
}