Skip to content

Commit

Permalink
Started parallelizing the generation (#62 from wesuRage/main)
Browse files Browse the repository at this point in the history
Started parallelizing the generation
  • Loading branch information
wesuRage authored Dec 18, 2024
2 parents 8714573 + e36c5db commit 3429217
Show file tree
Hide file tree
Showing 16 changed files with 207 additions and 48 deletions.
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.
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) {

}

0 comments on commit 3429217

Please sign in to comment.