Skip to content

Commit

Permalink
feat: Functions can now refer to each other without having to be decl…
Browse files Browse the repository at this point in the history
…ared in a certain order
  • Loading branch information
alinalihassan committed May 26, 2022
1 parent d21192d commit 7230883
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 57 deletions.
119 changes: 62 additions & 57 deletions src/liblesma/Backend/Codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,59 @@ llvm::Function *Codegen::InitializeTopLevel() {
return F;
}

void Codegen::defineFunction(Function *F, FuncDecl *node, SymbolTableEntry *clsSymbol) {
Scope = Scope->createChildBlock(node->getName());
deferStack.push({});

BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F);
Builder->SetInsertPoint(BB);

for (auto &param: F->args()) {
if (clsSymbol != nullptr && param.getArgNo() == 0)
param.setName("self");
else
param.setName(node->getParameters()[param.getArgNo() - (clsSymbol != nullptr ? 1 : 0)].first);

llvm::Value *ptr;
ptr = Builder->CreateAlloca(param.getType(), nullptr, param.getName() + "_ptr");
Builder->CreateStore(&param, ptr);

auto symbol = new SymbolTableEntry(param.getName().str(), getType(param.getType()));
symbol->setLLVMType(param.getType());
symbol->setLLVMValue(ptr);
Scope->insertSymbol(symbol);
}

visit(node->getBody());

auto instrs = deferStack.top();
deferStack.pop();

if (!isReturn)
for (auto inst: instrs)
visit(inst);

if (F->getReturnType() == Builder->getVoidTy() && !isReturn)
Builder->CreateRetVoid();

isReturn = false;

// Verify function
// TODO: Verify function again, unfortunately functions from other modules have attributes attached without context of usage, and verify gives error
// std::string output;
// llvm::raw_string_ostream oss(output);
// if (llvm::verifyFunction(*F, &oss)) {
// F->print(outs());
// throw CodegenError(node->getSpan(), "Invalid Function {}\n{}", node->getName(), output);
// }

// Insert Function to Symbol Table
Scope = Scope->getParent();

// Reset Insert Point to Top Level
Builder->SetInsertPoint(&TopLevelFunc->back());
}

std::unique_ptr<llvm::TargetMachine> Codegen::InitializeTargetMachine() {
// Configure output target
auto targetTriple = llvm::Triple(llvm::sys::getDefaultTargetTriple());
Expand Down Expand Up @@ -251,6 +304,9 @@ void Codegen::Run() {
for (auto inst: instrs)
visit(inst);

for (auto prot: Prototypes)
defineFunction(std::get<0>(prot), std::get<1>(prot), std::get<2>(prot));

// Return 0 for top-level function
Builder->CreateRet(ConstantInt::getSigned(Builder->getInt64Ty(), 0));
}
Expand Down Expand Up @@ -462,8 +518,6 @@ void Codegen::visit(While *node) {
}

void Codegen::visit(FuncDecl *node) {
Scope = Scope->createChildBlock(node->getName());

if (classSymbol != nullptr && node->getName() == "new" && node->getReturnType()->getType() != TokenType::VOID_TYPE)
throw CodegenError(node->getSpan(), "Cannot create class method new with return type {}", node->getReturnType()->getName());

Expand All @@ -478,65 +532,16 @@ void Codegen::visit(FuncDecl *node) {

auto name = getMangledName(node->getSpan(), node->getName(), paramTypes, classSymbol != nullptr);
auto linkage = Function::ExternalLinkage;
auto ret_type = visit(node->getReturnType());

FunctionType *FT = FunctionType::get(ret_type, paramTypes, node->getVarArgs());
FunctionType *FT = FunctionType::get(visit(node->getReturnType()), paramTypes, node->getVarArgs());
Function *F = Function::Create(FT, linkage, name, *TheModule);

auto symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType(F->getFunctionType());
symbol->setLLVMValue(F);
Scope->getParent()->insertSymbol(symbol);
auto func_symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
func_symbol->setLLVMType(F->getFunctionType());
func_symbol->setLLVMValue(F);
Scope->insertSymbol(func_symbol);

deferStack.push({});

BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F);
Builder->SetInsertPoint(BB);

for (auto &param: F->args()) {
if (classSymbol != nullptr && param.getArgNo() == 0)
param.setName("self");
else
param.setName(node->getParameters()[param.getArgNo() - (classSymbol != nullptr ? 1 : 0)].first);

llvm::Value *ptr;
ptr = Builder->CreateAlloca(param.getType(), nullptr, param.getName() + "_ptr");
Builder->CreateStore(&param, ptr);

auto symbol = new SymbolTableEntry(param.getName().str(), getType(param.getType()));
symbol->setLLVMType(param.getType());
symbol->setLLVMValue(ptr);
Scope->insertSymbol(symbol);
}

visit(node->getBody());

auto instrs = deferStack.top();
deferStack.pop();

if (!isReturn)
for (auto inst: instrs)
visit(inst);

if (ret_type == Builder->getVoidTy() && !isReturn)
Builder->CreateRetVoid();

isReturn = false;

// Verify function
// TODO: Verify function again, unfortunately functions from other modules have attributes attached without context of usage, and verify gives error
// std::string output;
// llvm::raw_string_ostream oss(output);
// if (llvm::verifyFunction(*F, &oss)) {
// F->print(outs());
// throw CodegenError(node->getSpan(), "Invalid Function {}\n{}", node->getName(), output);
// }

// Insert Function to Symbol Table
Scope = Scope->getParent();

// Reset Insert Point to Top Level
Builder->SetInsertPoint(&TopLevelFunc->back());
Prototypes.emplace_back(F, node, classSymbol);
}

void Codegen::visit(ExternFuncDecl *node) {
Expand Down
2 changes: 2 additions & 0 deletions src/liblesma/Backend/Codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ namespace lesma {

std::vector<std::string> ObjectFiles;
std::vector<std::string> ImportedModules;
std::vector<std::tuple<Function*, FuncDecl *, SymbolTableEntry *>> Prototypes;
llvm::Function *TopLevelFunc;
SymbolTableEntry *classSymbol = nullptr;
bool isBreak = false;
Expand Down Expand Up @@ -108,5 +109,6 @@ namespace lesma {
std::string getTypeMangledName(llvm::SMRange span, llvm::Type *type);
llvm::Value *genFuncCall(FuncCall *node, const std::vector<llvm::Value *> &extra_params);
static int FindIndexInFields(SymbolType *_struct, const std::string &field);
void defineFunction(Function *F, FuncDecl *node, SymbolTableEntry *clsSymbol);
};
}// namespace lesma

0 comments on commit 7230883

Please sign in to comment.