Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Started parallelizing the generation #62

Merged
merged 12 commits into from
Dec 18, 2024
Merged
15 changes: 10 additions & 5 deletions examples/a.glx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
def main( ) -> int:
int num := 3;
int quatro := num + 1;
return quatro;
end;
def tigres_de_bengala( int numero) -> int:
int num := numero;
int quatro := num + 1;
return numero ;
end;

def main( ) -> int:
int num := 3;
int quatro := num + 1;
return tigres_de_bengala( quatro) ; ;
end;
28 changes: 28 additions & 0 deletions include/backend/generator/parallel/queue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef QUEUE_H
#define QUEUE_H

extern "C" {
#include "frontend/ast/definitions.h"
}

#include <future>
#include <mutex>
#include <queue>
#include <condition_variable>

struct PendingIdentifier {
IdentifierNode *node;
std::promise<llvm::Value*> promise;
};

// Tabela de símbolos e fila de pendências
extern std::mutex symbolTableMutex;
extern std::queue<PendingIdentifier> pendingQueue;
extern std::condition_variable pendingCondition;

llvm::Value* find_or_wait_for_identifier(IdentifierNode *node);

void process_pending_identifiers_async();
void process_pending_identifiers_periodically();

#endif // QUEUE_H
5 changes: 4 additions & 1 deletion include/backend/generator/symbols/symbol_stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <unordered_map>
#include <stack>
#include <llvm/IR/Value.h>
#include <mutex> // Include for std::mutex

struct SymbolInfo {
llvm::Value* value;
Expand All @@ -14,7 +15,9 @@ struct SymbolInfo {
using SymbolTable = std::unordered_map<std::string, SymbolInfo>;

extern std::stack<SymbolTable> symbol_stack;
extern std::mutex symbol_stack_mutex;

void enter_scope(void);
void exit_scope(void);

#endif // SYMBOL_STACK_H
#endif // SYMBOL_STACK_H
File renamed without changes.
4 changes: 4 additions & 0 deletions src/backend/generator/expressions/generate_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ llvm::Value *generate_call(CallNode *call_node, llvm::LLVMContext &Context, llvm
arg = Builder.CreateIntCast(arg, expected_type, true);
} else if (arg->getType()->isFloatingPointTy() && expected_type->isFloatingPointTy()) {
arg = Builder.CreateFPCast(arg, expected_type);
} else if (arg->getType()->isPointerTy() && expected_type->isIntegerTy()) {
arg = Builder.CreatePointerCast(arg, expected_type);
} else if (arg->getType()->isPointerTy() && expected_type->isFloatingPointTy()) {
arg = Builder.CreatePointerCast(arg, expected_type);
} else {
throw std::runtime_error("Argument type mismatch.");
}
Expand Down
4 changes: 0 additions & 4 deletions src/backend/generator/expressions/generate_expr.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
#include <future>
#include <vector>
#include <stdexcept>
#include <mutex>
#include "backend/generator/expressions/generate_expr.hpp"
#include "backend/generator/expressions/generate_numeric_literal.hpp"
#include "backend/generator/expressions/generate_identifier.hpp"
Expand Down
10 changes: 5 additions & 5 deletions src/backend/generator/expressions/generate_identifier.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include "backend/generator/expressions/generate_identifier.hpp"
#include "backend/generator/symbols/identifier_symbol_table.hpp"
#include "backend/generator/parallel/queue.hpp"

llvm::Value *generate_identifier(IdentifierNode *node) {
const SymbolInfo *id = find_identifier(node->symbol);

if (!id) {
try {
return find_or_wait_for_identifier(node);
} catch (...) {
throw std::runtime_error("Error: identifier not found!");
}

return id->value;
}

75 changes: 60 additions & 15 deletions src/backend/generator/generator.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,70 @@
#include <vector>
#include "backend/generator/generate_ir.hpp"
#include "backend/generator/statements/generate_stmt.hpp"
#include <future>
#include <mutex>

std::vector<llvm::Value*> generate_ir(AstNode *node, llvm::LLVMContext &Context, llvm::Module &Module, llvm::IRBuilder<> &Builder) {
// Cast the AstNode to ProgramNode as the data in AstNode is assumed to be a ProgramNode
ProgramNode *program = (ProgramNode *)node->data;
// Estrutura intermediária personalizada para armazenar informações de IR
struct IntermediateIR {
std::string blockName;
std::vector<llvm::Instruction*> instructions;
};

// Vector to hold the generated LLVM IR values
std::vector<llvm::Value*> IRs;
// Função principal de geração
std::vector<llvm::Value*> generate_ir(AstNode *node, llvm::LLVMContext &mainContext, llvm::Module &mainModule, llvm::IRBuilder<> &mainBuilder) {
ProgramNode *program = static_cast<ProgramNode *>(node->data);
std::vector<std::future<IntermediateIR>> futures;
std::vector<IntermediateIR> intermediateIRs;

// Iterate over all statements in the program and generate their corresponding IR
// Geração paralela de IR
for (size_t i = 0; i < program->statement_count; ++i) {
// Generate LLVM IR for each statement
llvm::Value *IR = generate_stmt(program->statements[i], Context, Module, Builder);

// If the generated IR is not null, add it to the result vector
if (IR) {
IRs.push_back(IR);
AstNode *statement = program->statements[i];

futures.push_back(std::async(std::launch::async, [statement]() -> IntermediateIR {
// Criar estrutura intermediária para esta thread
IntermediateIR ir;
ir.blockName = "Block_" + std::to_string(std::hash<std::thread::id>{}(std::this_thread::get_id()));

// Criar contexto, módulo e IRBuilder para esta thread
llvm::LLVMContext threadContext;
llvm::Module threadModule("ThreadModule", threadContext);
llvm::IRBuilder<> threadBuilder(threadContext);

llvm::Value* result = generate_stmt(statement, threadContext, threadModule, threadBuilder);
if (auto *inst = llvm::dyn_cast<llvm::Instruction>(result)) {
ir.instructions.push_back(inst); // Adicionar instrução gerada
}

return ir;
}));
}

// Coletar resultados das threads
for (auto &future : futures) {
try {
intermediateIRs.push_back(future.get());
} catch (const std::exception &e) {
llvm::errs() << "Exception during future.get(): " << e.what() << "\n";
} catch (...) {
llvm::errs() << "Unknown exception during future.get()\n";
}
}

// Concatenar IRs intermediários no contexto principal
for (const auto &ir : intermediateIRs) {
// Criar um novo bloco no contexto principal

/*
* O segfault ocorre no getParent
*/

llvm::BasicBlock *block = llvm::BasicBlock::Create(mainContext, ir.blockName, mainBuilder.GetInsertBlock()->getParent());
mainBuilder.SetInsertPoint(block); // Estabelecer ponto de inserção no novo bloco

// Inserir as instruções no bloco
for (auto *inst : ir.instructions) {
mainBuilder.Insert(inst); // Adicionar instrução ao bloco principal
}
}

// Return the vector containing the generated IR for the statements
return IRs;
return {};
}
8 changes: 7 additions & 1 deletion src/backend/generator/generator.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "backend/generator/generate_ir.hpp"
#include "backend/generator/symbols/symbol_stack.hpp"
#include "backend/generator/parallel/queue.hpp"

extern "C" {
#include "frontend/lexer/core.h"
Expand Down Expand Up @@ -66,6 +67,9 @@ int main(int argc, char **argv) {
printf("-----------------\n");
print_ast(ast);

printf("\nGeneration:\n");
printf("-----------------\n");

// Initialize LLVM target-related components (needed to generate machine code)
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
Expand All @@ -81,7 +85,9 @@ int main(int argc, char **argv) {
// Create the global scope
enter_scope();

// Generate the LLVM IR from the AST
std::thread pendingThread(process_pending_identifiers_periodically);
pendingThread.detach();

std::vector<llvm::Value*> values = generate_ir(ast, TheContext, TheModule, Builder);

// Print out the generated LLVM IR for debugging
Expand Down
62 changes: 62 additions & 0 deletions src/backend/generator/parallel/queue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "backend/generator/expressions/generate_identifier.hpp"
#include "backend/generator/symbols/identifier_symbol_table.hpp"
#include "backend/generator/parallel/queue.hpp"

std::mutex symbolTableMutex;
std::queue<PendingIdentifier> pendingQueue;
std::condition_variable pendingCondition;

// Função para encontrar um identificador ou adicionar à fila de pendências
llvm::Value* find_or_wait_for_identifier(IdentifierNode* node) {
std::unique_lock<std::mutex> lock(symbolTableMutex);

// Tentar encontrar o identificador na tabela de símbolos
const SymbolInfo* id = find_identifier(node->symbol);
if (id) {
return id->value;
}

// Se não encontrar, criar uma pendência
PendingIdentifier pending{node};
std::promise<llvm::Value*> promise;
pending.promise = std::move(promise);
auto future = pending.promise.get_future();

// Adicionar à fila de pendências
pendingQueue.push(std::move(pending));
pendingCondition.notify_all();

lock.unlock(); // Desbloquear a tabela de símbolos para permitir outros acessos

// Esperar pela resolução do identificador
return future.get();
}

// Processar as pendências de identificadores de forma assíncrona
void process_pending_identifiers_async() {
std::unique_lock<std::mutex> lock(symbolTableMutex);

// Processar a fila de pendências enquanto houver identificadores pendentes
while (!pendingQueue.empty()) {
PendingIdentifier pending = std::move(pendingQueue.front());
pendingQueue.pop();

// Verificar novamente a tabela de símbolos
const SymbolInfo* id = find_identifier(pending.node->symbol);
if (id) {
// Resolver a pendência, setando o valor
pending.promise.set_value(id->value);
} else {
// Se não encontrar, re-adiciona à fila
pendingQueue.push(std::move(pending));
}
}
}

// Função para ser chamada em outro thread que processa as pendências
void process_pending_identifiers_periodically() {
while (true) {
process_pending_identifiers_async();
}
}

16 changes: 4 additions & 12 deletions src/backend/generator/statements/generate_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,23 @@
#include "backend/generator/statements/generate_function_declaration_stmt.hpp"
#include "backend/generator/statements/generate_extern_stmt.hpp"
#include "backend/generator/expressions/generate_expr.hpp"
#include <future>

llvm::Value* generate_stmt(AstNode *node, llvm::LLVMContext &Context, llvm::Module &Module, llvm::IRBuilder<> &Builder) {
switch (node->kind) {
case NODE_VARIABLE: {
VariableNode *varNode = (VariableNode *)node->data;
generate_variable_declaration_stmt(varNode, Context, Builder, Module);

return nullptr;
return generate_variable_declaration_stmt(varNode, Context, Builder, Module);
}
case NODE_FUNCTION: {
FunctionNode *funcNode = (FunctionNode *)node->data;
generate_function_declaration_stmt(funcNode, Context, Builder, Module);

return nullptr;
return generate_function_declaration_stmt(funcNode, Context, Builder, Module);
}
case NODE_EXTERN: {
ExternNode *externNode = (ExternNode *)node->data;
generate_extern_stmt(externNode, Context, Builder, Module);

return nullptr;
return generate_extern_stmt(externNode, Context, Builder, Module);
}

default: {
return generate_expr(node, Context, Builder, Module);
return generate_expr(node, Context, Builder, Module); // Para expressões, o valor gerado
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ llvm::Value* generate_variable_declaration_stmt(VariableNode *node, llvm::LLVMCo
}

// Stores the allocated variable in the identifier symbol table
add_identifier(node->name, alloca, var_type);
{
std::lock_guard<std::mutex> lock(symbol_stack_mutex);
add_identifier(node->name, alloca, var_type);
}

return alloca;
}
5 changes: 4 additions & 1 deletion src/backend/generator/symbols/identifier_symbol_table.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#include "backend/generator/symbols/identifier_symbol_table.hpp"
#include "backend/generator/symbols/symbol_stack.hpp"

const SymbolInfo* find_identifier(const std::string &name) {
const SymbolInfo *find_identifier(const std::string &name) {
std::lock_guard<std::mutex> lock(symbol_stack_mutex);

for (const auto& entry : symbol_stack.top()) {
if (entry.first == name) {
return &entry.second;
}
}

return nullptr;
}

Expand Down
7 changes: 4 additions & 3 deletions src/backend/generator/symbols/symbol_stack.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#include "backend/generator/symbols/symbol_stack.hpp"
#include "backend/generator/symbols/identifier_symbol_table.hpp"

std::stack<SymbolTable> symbol_stack;

std::mutex symbol_stack_mutex;

void enter_scope() {
// Adiciona uma nova tabela de símbolos ao topo da pilha
std::lock_guard<std::mutex> lock(symbol_stack_mutex);
symbol_stack.push(SymbolTable{});
}

void exit_scope() {
// Remove a tabela de símbolos do topo da pilha
std::lock_guard<std::mutex> lock(symbol_stack_mutex);
if (symbol_stack.empty()) {
throw std::runtime_error("Exiting scope when no scope exists!");
}
Expand Down
11 changes: 11 additions & 0 deletions src/frontend/checker/checker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <iostream>

extern "C" {
#include "frontend/checker/core.h"
#include "frontend/checker/common_types.h"
#include "utils.h"
}

Checker* init(AstNode* ast) {

}
Loading