Skip to content

Commit

Permalink
For loop generation implemented (#63 from wesuRage/main)
Browse files Browse the repository at this point in the history
For loop generation implemented
  • Loading branch information
wesuRage authored Dec 20, 2024
2 parents 8b81786 + a08d384 commit e7e2898
Show file tree
Hide file tree
Showing 29 changed files with 476 additions and 114 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*_test
*_main
*.tree
*.ll
.idea/
.vscode/
gdb.txt
Expand Down
26 changes: 18 additions & 8 deletions examples/a.glx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
def tigres_de_bengala( int numero) -> int:
int num := numero;
int quatro := num + 1;
return numero ;
end;
extern int write( int, string, int) ;
extern int putchar( int) ;

def main( ) -> int:
int num := 3;
int quatro := num + 1;
return tigres_de_bengala( quatro) ; ;

int linhas := 10;
int colunas := 10;
int chunks := 3;

for ( int k := 0; k < chunks; ++ k ) :
for ( int i := 0; i < linhas; ++ i ) :
for ( int j := 0; j < colunas; ++ j ) :
int var := write( 1, "a", 1) ; ;
end;
int foo := putchar( 10) ; ;
end;
int bar := putchar( 10) ; ;
end;

return 0;
end;
4 changes: 2 additions & 2 deletions include/backend/generator/parallel/queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ struct PendingIdentifier {
extern std::mutex symbolTableMutex;
extern std::queue<PendingIdentifier> pendingQueue;
extern std::condition_variable pendingCondition;
extern std::string global_id_return;

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

llvm::Value* find_or_wait_for_identifier(IdentifierNode* node, std::string return_type);
void process_pending_identifiers_async();
void process_pending_identifiers_periodically();

Expand Down
16 changes: 16 additions & 0 deletions include/backend/generator/statements/generate_for_stmt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef GENERATE_FOR_STMT_H
#define GENERATE_FOR_STMT_H

extern "C" {
#include "frontend/ast/definitions.h"
}
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/Value.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/BasicBlock.h>

llvm::Value* generate_for_stmt(ForNode *node, llvm::LLVMContext &Context, llvm::IRBuilder<> &Builder, llvm::Module &Module);

#endif // GENERATE_FOR_STMT_H
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
#include "backend/generator/symbols/symbol_stack.hpp"

const SymbolInfo *find_identifier(const std::string &name);
void add_identifier(const std::string &name, llvm::Value* value, llvm::Type* type);
void add_identifier(const std::string &name, llvm::Value* declaration, llvm::Value* value, llvm::Type* type);

#endif // IDENTIFIER_SYMBOL_TABLE_H
13 changes: 13 additions & 0 deletions include/backend/generator/symbols/string_symbol_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef STRING_SYMBOL_TABLE_H
#define STRING_SYMBOL_TABLE_H

#include <unordered_map>
#include <string>
#include <llvm/IR/Value.h>

extern std::unordered_map<std::string, llvm::Value *> string_symbol_table;

void add_string(const std::string &name, llvm::Value *value);
llvm::Value *find_string(const std::string &name);

#endif // STRING_SYMBOL_TABLE_H
1 change: 1 addition & 0 deletions include/backend/generator/symbols/symbol_stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <mutex> // Include for std::mutex

struct SymbolInfo {
llvm::Value* declaration;
llvm::Value* value;
llvm::Type* type;
};
Expand Down
12 changes: 12 additions & 0 deletions include/frontend/ast/definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,20 @@ typedef struct {
AstNode *stop;
AstNode *updater;
AstNode *iterator;
bool is_parallel;
char *schedule_policy; // "static", "dynamic"
AstNode *num_threads;
} ForNode;

typedef struct {
char *type; // "barrier", "atomic"
} SyncNode;

typedef struct {
char *name;
char *memory_type; // "private", "shared", "pgas"
} MemoryNode;

typedef struct {
AstNode *condition;
AstNode **consequent;
Expand Down
3 changes: 3 additions & 0 deletions include/frontend/lexer/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ typedef enum {
TOKEN_OBRACKET,
TOKEN_CBRACKET,
TOKEN_EXTERN,
TOKEN_STATIC,
TOKEN_DYNAMIC,
TOKEN_PARALLEL,
TOKEN_UNKNOWN,
} TokenType;

Expand Down
133 changes: 133 additions & 0 deletions libs/lib.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
@new_line = constant [1 x i8] c"\0A" ; Define a constant representing the newline character (0x0A)

declare i64 @write(i32, ptr, i64) ; Declare the write syscall, which takes a file descriptor (i32), a pointer to data (ptr), and the length of the data (i64)

; Implementation of writeln
define i64 @writeln(ptr %str) {
entry:
; Calculate the length of the string by calling strlen
%len = call i64 @strlen(ptr %str)

; Call the write syscall to print the string
call i64 @write(i32 1, ptr %str, i64 %len) ; Write the string to stdout (file descriptor 1)

; Get the pointer to the newline character
%newline_ptr = getelementptr [1 x i8], [1 x i8]* @new_line, i64 0, i64 0

; Call the write syscall again to print the newline
%return = call i64 @write(i32 1, ptr %newline_ptr, i64 1) ; Write the newline to stdout

ret i64 %return ; Return from the writeln function
}

define i64 @strlen(ptr %input_str) {
entry:
; Allocate memory to store the starting pointer of the string
%start_ptr = alloca ptr, align 8
; Allocate memory to store the current pointer for iteration
%current_ptr = alloca ptr, align 8

; Store the input string pointer in start_ptr
store ptr %input_str, ptr %start_ptr, align 8
; Load the initial pointer and store it in current_ptr for iteration
%loaded_start = load ptr, ptr %start_ptr, align 8
store ptr %loaded_start, ptr %current_ptr, align 8

; Jump to the loop head to start processing the string
br label %loop_head

loop_head: ; preds = %loop_body, %entry
; Load the current pointer to get the character it points to
%current_char_ptr = load ptr, ptr %current_ptr, align 8
; Load the character at the current pointer
%current_char = load i8, ptr %current_char_ptr, align 1
; Check if the character is not the null terminator (0)
%current_char_as_int = sext i8 %current_char to i32

%is_not_null = icmp ne i32 %current_char_as_int, 0
; If not null, continue the loop; otherwise, exit
br i1 %is_not_null, label %loop_body, label %done

loop_body: ; preds = %loop_head
; Load the current pointer
%current_ptr_loaded = load ptr, ptr %current_ptr, align 8
; Get the pointer to the next character in the string
%next_char_ptr = getelementptr inbounds i8, ptr %current_ptr_loaded, i32 1
; Store the updated pointer back to current_ptr
store ptr %next_char_ptr, ptr %current_ptr, align 8
; Go back to the loop head to process the next character
br label %loop_head

done: ; preds = %loop_head
; Load the final pointer after reaching the null terminator
%final_ptr = load ptr, ptr %current_ptr, align 8
; Load the initial pointer stored in start_ptr
%initial_ptr = load ptr, ptr %start_ptr, align 8
; Convert the final pointer to an integer
%final_ptr_as_int = ptrtoint ptr %final_ptr to i64
; Convert the initial pointer to an integer
%initial_ptr_as_int = ptrtoint ptr %initial_ptr to i64
; Subtract the initial pointer value from the final pointer value to get the string length
%string_length = sub i64 %final_ptr_as_int, %initial_ptr_as_int
; Return the calculated string length
ret i64 %string_length
}

@strrep.temp_buffer = internal global [1024 x i8] zeroinitializer, align 16

define ptr @strrep(ptr %input_str, i32 %repeat_count) {
entry:
; Allocate space for intermediate variables
%output_buffer = alloca ptr, align 8
%string_ptr = alloca ptr, align 8
%repeat_index = alloca i32, align 4
%temp_index = alloca i32, align 4

; Initialize variables
store ptr %input_str, ptr %string_ptr, align 8
store i32 0, ptr %repeat_index, align 4
store i32 0, ptr %temp_index, align 4

br label %check_repeat_loop

check_repeat_loop: ; Check if repetition loop is complete
%repeat_count_val = load i32, ptr %repeat_index, align 4
%is_repeat_done = icmp sge i32 %repeat_count_val, %repeat_count
br i1 %is_repeat_done, label %finalize_buffer, label %copy_to_temp_buffer

copy_to_temp_buffer: ; Copy characters to the buffer
%current_str_ptr = load ptr, ptr %string_ptr, align 8
%temp_index_val = load i32, ptr %temp_index, align 4
%char_pos = sext i32 %temp_index_val to i64
%char_ptr = getelementptr inbounds i8, ptr %current_str_ptr, i64 %char_pos
%char_val = load i8, ptr %char_ptr, align 1
%is_non_null = icmp ne i8 %char_val, 0
br i1 %is_non_null, label %continue_copying, label %increment_repeat_index

continue_copying: ; Copy single character to the temp buffer
%temp_offset = load i32, ptr %temp_index, align 4
%buffer_pos = getelementptr inbounds [1024 x i8], ptr @strrep.temp_buffer, i64 0, i32 %temp_offset
store i8 %char_val, ptr %buffer_pos, align 1
%next_index = add nsw i32 %temp_offset, 1
store i32 %next_index, ptr %temp_index, align 4
br label %copy_to_temp_buffer

increment_repeat_index: ; Increment repeat index and reset temp index
%next_repeat = load i32, ptr %repeat_index, align 4
%incremented_repeat = add i32 %next_repeat, 1
store i32 %incremented_repeat, ptr %repeat_index, align 4
store i32 0, ptr %temp_index, align 4
br label %check_repeat_loop

finalize_buffer: ; Add null terminator and finalize buffer
%final_size = load i32, ptr %temp_index, align 4
%final_size64 = sext i32 %final_size to i64
%final_ptr = getelementptr inbounds [1024 x i8], ptr @strrep.temp_buffer, i64 0, i64 %final_size64
store i8 0, ptr %final_ptr, align 1
store ptr @strrep.temp_buffer, ptr %output_buffer, align 8
br label %return_buffer

return_buffer: ; Return the buffer
%final_output = load ptr, ptr %output_buffer, align 8
ret ptr %final_output
}
51 changes: 50 additions & 1 deletion src/backend/generator/expressions/generate_binary_expr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "backend/generator/expressions/generate_binary_expr.hpp"
#include "backend/generator/expressions/generate_expr.hpp"
#include "backend/generator/symbols/identifier_symbol_table.hpp"
#include "backend/generator/symbols/string_symbol_table.hpp"
#include "backend/generator/symbols/function_symbol_table.hpp"

llvm::Value *generate_binary_expr(BinaryExprNode *node, llvm::LLVMContext &Context, llvm::IRBuilder<> &Builder, llvm::Module &Module) {
llvm::Value *L = generate_expr(node->left, Context, Builder, Module);
Expand All @@ -16,10 +18,57 @@ llvm::Value *generate_binary_expr(BinaryExprNode *node, llvm::LLVMContext &Conte
bool isLPointer = LType->isPointerTy();
bool isRPointer = RType->isPointerTy();

llvm::errs() << L->getValueName() << "\n";
llvm::errs() << L->getValueName()->getValue()->getName().str() << "\n";

if (isLPointer) {
llvm::Value *string = find_string(L->getValueName()->getValue()->getName().str());
if (string) {
if (isRInteger && strcmp(node->op, "*") == 0) {
auto it = function_symbol_table.find("strrep");
if (it == function_symbol_table.end()) {
throw std::runtime_error("Function not found in symbol table: strrep");
}

llvm::Function *function = it->second;
llvm::FunctionType *func_type = function->getFunctionType();

// Prepare arguments for the strrep function
std::vector<llvm::Value *> args;
// The first argument is the string (L)
args.push_back(string);
// The second argument is the repetition count (R)
args.push_back(R);

// Ensure the types of the arguments are correct
for (size_t i = 0; i < args.size(); ++i) {
llvm::Value *arg = args[i];
llvm::Type *expected_type = func_type->getParamType(i);
if (arg->getType() != expected_type) {
if (arg->getType()->isIntegerTy() && expected_type->isIntegerTy()) {
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.");
}
}
args[i] = arg;
}

// Call the strrep function
llvm::Value *resultBuffer = Builder.CreateCall(function, args);
return resultBuffer;
}
}

const SymbolInfo* symbolInfo = find_identifier(static_cast<IdentifierNode*>(node->left->data)->symbol);
if (!symbolInfo) {
throw std::runtime_error("Unknown identifier for left operand");
throw std::runtime_error("Unsupported Left type for binary operation");
}
llvm::Type* pointeeType = symbolInfo->type;

Expand Down
4 changes: 4 additions & 0 deletions src/backend/generator/expressions/generate_call.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "backend/generator/expressions/generate_call.hpp"
#include "backend/generator/expressions/generate_expr.hpp"
#include "backend/generator/symbols/function_symbol_table.hpp"
#include "backend/generator/parallel/queue.hpp"

llvm::Value *generate_call(CallNode *call_node, llvm::LLVMContext &Context, llvm::IRBuilder<> &Builder, llvm::Module &Module) {
if (!call_node || !call_node->caller) {
Expand All @@ -23,6 +24,7 @@ llvm::Value *generate_call(CallNode *call_node, llvm::LLVMContext &Context, llvm
// Generate arguments
std::vector<llvm::Value *> args;
for (size_t i = 0; i < call_node->arg_count; ++i) {
global_id_return = "declaration";
llvm::Value *arg = generate_expr(call_node->args[i], Context, Builder, Module);
if (!arg) {
throw std::runtime_error("Failed to generate call argument.");
Expand All @@ -47,6 +49,8 @@ llvm::Value *generate_call(CallNode *call_node, llvm::LLVMContext &Context, llvm
args.push_back(arg);
}

global_id_return = "value";

// Create the call instruction
return Builder.CreateCall(function, args);
}
2 changes: 1 addition & 1 deletion src/backend/generator/expressions/generate_identifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

llvm::Value *generate_identifier(IdentifierNode *node) {
try {
return find_or_wait_for_identifier(node);
return find_or_wait_for_identifier(node, global_id_return);
} catch (...) {
throw std::runtime_error("Error: identifier not found!");
}
Expand Down
2 changes: 2 additions & 0 deletions src/backend/generator/expressions/generate_pre_decrement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ llvm::Value *generate_pre_decrement(PreDecrementExpr *node, llvm::LLVMContext &C
// Generate LLVM IR for the operand (the value to be decremented)
llvm::Value *Operand = generate_expr(node->op, Context, Builder, Module);

Operand = Builder.CreatePtrToInt(Operand, llvm::Type::getInt32Ty(Context));

// Create a subtraction instruction to decrement the operand by 1
// This is a pre-decrement operation, so the operand is decreased before returning the result.
llvm::Value *Decremented = Builder.CreateSub(Operand, llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), 1), "decpretmp");
Expand Down
2 changes: 2 additions & 0 deletions src/backend/generator/expressions/generate_pre_increment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
llvm::Value *generate_pre_increment(PreIncrementExpr *node, llvm::LLVMContext &Context, llvm::IRBuilder<> &Builder, llvm::Module &Module) {
// Generate LLVM IR for the operand (the value to be incremented)
llvm::Value *Operand = generate_expr(node->op, Context, Builder, Module);

Operand = Builder.CreatePtrToInt(Operand, llvm::Type::getInt32Ty(Context));

// Create an addition instruction to increment the operand by 1
// This is a pre-increment operation, so the operand is increased before returning the result.
Expand Down
Loading

0 comments on commit e7e2898

Please sign in to comment.