aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-04-24 21:22:53 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit7f524c427597cc998f243769b0e22e4f450c55cf (patch)
tree0dba782c2214d1ce5309ba71cfd3dddaee4a52a1
parent328a9c8310e8bab250b04e9e001ab0d890d33074 (diff)
Progressing on bytecode (to c), fix ssa resolving multiple times
-rw-r--r--doc/IMPLEMENTATION.md3
-rw-r--r--include/ast.h4
-rw-r--r--include/ssa/ssa.h4
-rw-r--r--include/std/file.h3
-rw-r--r--src/ast.c70
-rw-r--r--src/bytecode/bytecode.c103
-rw-r--r--src/compiler.c1
-rw-r--r--src/parser.c12
-rw-r--r--src/ssa/ssa.c74
-rw-r--r--src/std/file.c15
-rw-r--r--tests/b.amal.z4
-rw-r--r--tests/io.amal.z4
-rw-r--r--tests/main.amal.z36
-rw-r--r--tests/sub/a.amal.z2
14 files changed, 248 insertions, 87 deletions
diff --git a/doc/IMPLEMENTATION.md b/doc/IMPLEMENTATION.md
index 3956de2..387c6eb 100644
--- a/doc/IMPLEMENTATION.md
+++ b/doc/IMPLEMENTATION.md
@@ -16,5 +16,6 @@ is optimized before creating the bytecode.
1. Parsing using multiple threads is done, but the parser is not finished.
2. Resolving ast using multiple threads is done, but the ast resolver is not finished.
3. Generating ssa using multiple threads is done, but the ssa generator is not finished.
-4. Not started.
+4. Generating bytecode using multiple threads is done, but the bytecode generator is not finished.
+Currently it generates C code.
5. Not started. \ No newline at end of file
diff --git a/include/ast.h b/include/ast.h
index c010538..c40be22 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -57,7 +57,8 @@ typedef enum {
typedef enum {
AST_NOT_RESOLVED,
AST_RESOLVING,
- AST_RESOLVED
+ AST_RESOLVED,
+ AST_SSA_RESOLVED
} AstResolveStatus;
typedef struct {
@@ -69,6 +70,7 @@ typedef struct {
AstValue value;
AstType type;
AstResolveData resolve_data;
+ SsaRegister ssa_reg;
} Ast;
struct Scope {
diff --git a/include/ssa/ssa.h b/include/ssa/ssa.h
index 32d1ba6..e1e2d01 100644
--- a/include/ssa/ssa.h
+++ b/include/ssa/ssa.h
@@ -44,7 +44,8 @@ typedef struct {
Buffer/*instruction data*/ instructions;
HashMap/*<SsaNumber, SsaIntermediateIndex>*/ intermediates_map;
Buffer/*SsaNumber*/ intermediates;
- HashMap/*<BufferView, SsaStringIndex>*/ strings;
+ HashMap/*<BufferView, SsaStringIndex>*/ strings_map;
+ Buffer/*BufferView*/ strings;
SsaIntermediateIndex intermediate_counter;
SsaStringIndex string_counter;
SsaRegister reg_counter;
@@ -77,6 +78,7 @@ SsaNumber create_ssa_integer(i64 value);
SsaNumber create_ssa_float(f64 value);
SsaNumber ssa_get_intermediate(Ssa *self, SsaIntermediateIndex index);
+BufferView ssa_get_string(Ssa *self, SsaStringIndex index);
CHECK_RESULT int ssa_init(Ssa *self, ScopedAllocator *allocator);
CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result);
diff --git a/include/std/file.h b/include/std/file.h
index c6753fd..9184053 100644
--- a/include/std/file.h
+++ b/include/std/file.h
@@ -32,8 +32,7 @@ CHECK_RESULT int mapped_file_init(MappedFile *self, const char *filepath, Mapped
CHECK_RESULT int mapped_file_deinit(MappedFile *self);
#endif
-/* @data will be allocated with am_malloc, should be deallocated with am_free */
-CHECK_RESULT int read_whole_file(const char *filepath, char **data, usize *size);
+CHECK_RESULT int read_whole_file(const char *filepath, Buffer *result);
/* @result_path will be allocated with am_malloc, should be deallocated with am_free */
CHECK_RESULT int file_get_canonical_path(const char *filepath, char **result_path, usize *result_path_size);
diff --git a/src/ast.c b/src/ast.c
index 680eb50..983b3a4 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -4,6 +4,7 @@
#include "../include/std/log.h"
#include "../include/std/hash.h"
#include <assert.h>
+#include <stdarg.h>
#define throw(result) do { throw_debug_msg; longjmp(context->env, (result)); } while(0)
#define throw_if_error(result) \
@@ -26,6 +27,7 @@ int ast_create(ScopedAllocator *allocator, void *value, AstType type, Ast **resu
(*result)->value.data = value;
(*result)->type = type;
resolve_data_init(&(*result)->resolve_data);
+ (*result)->ssa_reg = 0;
return 0;
}
@@ -186,10 +188,23 @@ static Parser* scope_get_parser(Scope *scope) {
return scope->parser;
scope = scope->parent;
}
- assert(bool_false && "BUG: At least some scope parent is supposed to have a parser");
return NULL;
}
+static void parser_print_error(Parser *parser, const char *ref, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ if(parser) {
+ tokenizer_print_error(&parser->tokenizer,
+ tokenizer_get_code_reference_index(&parser->tokenizer, ref),
+ fmt, args);
+ } else {
+ /* TODO: Redirect error to compiler error callback if set */
+ amal_log_error(fmt, args);
+ }
+ va_end(args);
+}
+
static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) {
Ast *result;
bool exists;
@@ -203,9 +218,7 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context
return scope_get_resolved_variable(self->parent, context, name);
parser = scope_get_parser(self);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, name.data),
- "Undefined reference to variable \"%.*s\"", name.size, name.data);
+ parser_print_error(parser, name.data, "Undefined reference to variable \"%.*s\"", name.size, name.data);
throw(AST_ERR);
}
@@ -264,9 +277,8 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
if(ast->resolve_data.type && self->rhs_expr && ast->resolve_data.type != rhs_resolve_type) {
Parser *parser;
parser = scope_get_parser(context->scope);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, self->type.name.data),
- "Variable type and variable assignment type (right-hand side) do not match");
+ parser_print_error(parser, self->type.name.data,
+ "Variable type and variable assignment type (right-hand side) do not match");
throw(AST_ERR);
}
}
@@ -328,14 +340,11 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
callee_parser = get_resolved_type_parser(self);
callee_code_ref = self->resolve_data.type->var_name;
- tokenizer_print_error(&caller_parser->tokenizer,
- tokenizer_get_code_reference_index(&caller_parser->tokenizer, func_call->func.name.data),
+ parser_print_error(caller_parser, func_call->func.name.data,
"\"%.*s\" is not a function. Only functions can be called", func_call->func.name.size, func_call->func.name.data);
/* TODO: use tokenizer_print_note, once it has been added */
/* TODO: Print type */
- tokenizer_print_error(&callee_parser->tokenizer,
- tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data),
- "Type was declared here");
+ parser_print_error(callee_parser, callee_code_ref.data, "Type was declared here");
throw(AST_ERR);
}
@@ -375,9 +384,7 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
/* TODO: Allow field access for numbers and string as well */
BufferView code_ref;
code_ref = ast_get_code_reference(self->lhs);
- tokenizer_print_error(&caller_parser->tokenizer,
- tokenizer_get_code_reference_index(&caller_parser->tokenizer, code_ref.data),
- "Accessing fields is only applicable for variables");
+ parser_print_error(caller_parser, code_ref.data, "Accessing fields is only applicable for variables");
throw(AST_ERR);
}
@@ -389,26 +396,18 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
callee_code_ref = self->rhs->resolve_data.type->var_name;
if(self->lhs->resolve_data.type->rhs_expr->type != AST_STRUCT_DECL) {
- tokenizer_print_error(&caller_parser->tokenizer,
- tokenizer_get_code_reference_index(&caller_parser->tokenizer, caller_code_ref.data),
- "Can only access field of structs");
+ parser_print_error(caller_parser, caller_code_ref.data, "Can only access field of structs");
/* TODO: use tokenizer_print_note, once it has been added */
/* TODO: Print type */
- tokenizer_print_error(&callee_parser->tokenizer,
- tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data),
- "Type was declared here");
+ parser_print_error(callee_parser, callee_code_ref.data, "Type was declared here");
throw(AST_ERR);
}
if(!self->rhs->resolve_data.type->is_pub) {
- tokenizer_print_error(&caller_parser->tokenizer,
- tokenizer_get_code_reference_index(&caller_parser->tokenizer, caller_code_ref.data),
- "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data);
+ parser_print_error(caller_parser, caller_code_ref.data, "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data);
/* TODO: use tokenizer_print_note, once it has been added */
/* TODO: Print type */
- tokenizer_print_error(&callee_parser->tokenizer,
- tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data),
- "Type was declared non-public here");
+ parser_print_error(callee_parser, callee_code_ref.data, "Type was declared non-public here");
throw(AST_ERR);
}
}
@@ -437,17 +436,14 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) {
*/
Parser *parser;
parser = scope_get_parser(context->scope);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->rhs).data),
+ parser_print_error(parser, ast_get_code_reference(self->rhs).data,
"Can't cast type \"%.*s\" to type \"%.*s\"",
self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data,
self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->lhs).data),
+ parser_print_error(parser, ast_get_code_reference(self->lhs).data,
"Left-hand side is of type %.*s",
self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->rhs).data),
+ parser_print_error(parser, ast_get_code_reference(self->rhs).data,
"Right-hand side is of type %.*s",
self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data);
throw(AST_ERR);
@@ -474,9 +470,7 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
} else if(self->resolve_data.status == AST_RESOLVING) {
Parser *parser;
parser = scope_get_parser(context->scope);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self).data),
- "Found recursive dependency");
+ parser_print_error(parser, ast_get_code_reference(self).data, "Found recursive dependency");
throw(AST_ERR);
}
@@ -489,9 +483,7 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
Parser *parser;
parser = scope_get_parser(context->scope);
amal_mutex_tryunlock(self->value.lhs_expr->mutex);
- tokenizer_print_error(&parser->tokenizer,
- tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self).data),
- "Found recursive dependency");
+ parser_print_error(parser, ast_get_code_reference(self).data, "Found recursive dependency");
throw(AST_ERR);
}
}
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 7feb185..6774a54 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -2,7 +2,11 @@
#include "../../include/std/mem.h"
#include "../../include/ssa/ssa.h"
#include "../../include/parser.h"
+#include "../../include/compiler.h"
#include <assert.h>
+#include <stdio.h> /* TODO: Remove this */
+#include <stdlib.h>
+#include <string.h>
#define throw(result) do { throw_debug_msg; longjmp(self->env, (result)); } while(0)
#define throw_if_error(result) \
@@ -62,6 +66,8 @@ static void add_intermediates(BytecodeCompilerContext *self) {
}
}
+#define NUM_MAX_REGS 256
+
static void add_instructions(BytecodeCompilerContext *self) {
Ssa *ssa;
u8 *instruction;
@@ -70,10 +76,26 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaInsForm2 ssa_ins_form2;
SsaInsFuncStart ssa_ins_func_start;
SsaInsFuncCall ssa_ins_func_call;
+ FILE *file;
+ char *filename;
+ LhsExpr *reg_types[NUM_MAX_REGS]; /* TODO: Remove this. Encode this data in the register itself */
ssa = self->parser->ssa;
instruction = buffer_begin(&ssa->instructions);
instructions_end = buffer_end(&ssa->instructions);
+ /*#warning "dont forget to remove this" */
+ filename = malloc(self->parser->tokenizer.code_name.size + 3);
+ filename[0] = '\0';
+ strcat(filename, self->parser->tokenizer.code_name.data);
+ strcat(filename, ".z");
+ file = fopen(filename, "wb");
+ free(filename);
+ #ifdef DEBUG
+ am_memset(reg_types, 0, sizeof(reg_types));
+ #endif
+
+ fputs("typedef i64 signed long long;\n", file);
+ fputs("typedef f64 double;\n", file);
while(instruction != instructions_end) {
switch(*instruction++) {
@@ -81,43 +103,108 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaNumber number;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
number = ssa_get_intermediate(ssa, ssa_ins_form1.rhs);
- (void)number;
+ assert(ssa_ins_form1.lhs < NUM_MAX_REGS);
+ if(number.type == SSA_NUMBER_TYPE_INTEGER) {
+ fprintf(file, "i64 r%d = %zu;\n", ssa_ins_form1.lhs, number.value.integer);
+ reg_types[ssa_ins_form1.lhs] = self->parser->compiler->default_types.i64;
+ } else if(number.type == SSA_NUMBER_TYPE_FLOAT) {
+ fprintf(file, "f64 r%d = %f;\n", ssa_ins_form1.lhs, number.value.floating);
+ reg_types[ssa_ins_form1.lhs] = self->parser->compiler->default_types.f64;
+ } else {
+ assert(bool_false && "TODO: Implement");
+ }
break;
}
- case SSA_ASSIGN_STRING:
+ case SSA_ASSIGN_STRING: {
+ BufferView str;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ str = ssa_get_string(ssa, ssa_ins_form1.rhs);
+ fprintf(file, "const char* r%d = \"%.*s\";\n", ssa_ins_form1.lhs, (int)str.size, str.data);
+ assert(ssa_ins_form1.lhs < NUM_MAX_REGS);
+ reg_types[ssa_ins_form1.lhs] = self->parser->compiler->default_types.str;
break;
- case SSA_ASSIGN_REG:
+ }
+ case SSA_ASSIGN_REG: {
+ LhsExpr *rhs_type;
+ const char *rhs_type_name;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ assert(ssa_ins_form1.rhs < NUM_MAX_REGS);
+ rhs_type = reg_types[ssa_ins_form1.rhs];
+ if(rhs_type == self->parser->compiler->default_types.i64) {
+ rhs_type_name = "i64";
+ } else if(rhs_type == self->parser->compiler->default_types.f64) {
+ rhs_type_name = "f64";
+ } else if(rhs_type == self->parser->compiler->default_types.str) {
+ rhs_type_name = "const char*";
+ } else {
+ amal_log_error("Invalid rhs type %p for reg %d", rhs_type, ssa_ins_form1.rhs);
+ assert(bool_false && "TODO: Implement");
+ }
+ fprintf(file, "%s r%d = r%d;\n", rhs_type_name, ssa_ins_form1.lhs, ssa_ins_form1.rhs);
break;
- case SSA_ADD:
+ }
+ case SSA_ADD: {
instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ fprintf(file, "r%d = r%d + r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
+ assert(ssa_ins_form2.result < NUM_MAX_REGS);
+ assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
break;
- case SSA_SUB:
+ }
+ case SSA_SUB: {
instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ fprintf(file, "r%d = r%d - r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
+ assert(ssa_ins_form2.result < NUM_MAX_REGS);
+ assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
break;
- case SSA_MUL:
+ }
+ case SSA_MUL: {
instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ fprintf(file, "r%d = r%d * r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
+ assert(ssa_ins_form2.result < NUM_MAX_REGS);
+ assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
break;
- case SSA_DIV:
+ }
+ case SSA_DIV: {
instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ fprintf(file, "r%d = r%d / r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
+ assert(ssa_ins_form2.result < NUM_MAX_REGS);
+ assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
break;
- case SSA_FUNC_START:
+ }
+ case SSA_FUNC_START: {
+ int i;
instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start);
+ fprintf(file, "void f%zu(", ssa_ins_func_start.func_index);
+ fputs(") {\n", file);
+ for(i = 0; i < ssa_ins_func_start.num_args; ++i) {
+ if(i > 0)
+ fputs(", ", file);
+ fprintf(file, "p%d", i);
+ }
break;
+ }
case SSA_FUNC_END:
+ fputs("}\n", file);
break;
case SSA_PUSH: {
SsaRegister reg;
am_memcpy(&reg, instruction, sizeof(SsaRegister));
instruction += sizeof(SsaRegister);
+ fprintf(file, "PUSH r%d ***\n", reg);
break;
}
case SSA_CALL:
instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
+ fprintf(file, "r%d = CALL %p ***\n", ssa_ins_func_call.result, ssa_ins_func_call.func_decl);
break;
}
}
+
+ fclose(file);
}
void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
diff --git a/src/compiler.c b/src/compiler.c
index 3a921c3..30a583a 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -464,6 +464,7 @@ static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const cha
result_path = NULL;
*new_entry = bool_false;
+ /* TODO: Optimize. No need to allocate everytime... */
return_if_error(file_get_canonical_path(filepath, &result_path, &result_path_size));
path_view = create_buffer_view(result_path, result_path_size);
cleanup_if_error(amal_mutex_lock(&compiler->mutex, "try_create_file_scope"));
diff --git a/src/parser.c b/src/parser.c
index 8e122fd..f05b31d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -598,17 +598,13 @@ int parser_parse_buffer(Parser *self, BufferView code_buffer, BufferView buffer_
}
int parser_parse_file(Parser *self, BufferView filepath) {
- int result;
- char *file_data;
- usize file_size;
-
+ Buffer file_content;
+ return_if_error(buffer_init(&file_content, self->allocator));
assert(!self->started && "Parser can't be reused. Create a new parser.");
self->started = bool_true;
assert(filepath.size > 0 && filepath.data[filepath.size] == '\0');
- result = read_whole_file(filepath.data, &file_data, &file_size);
- if(result != 0) return result;
- result = parser_parse_buffer(self, create_buffer_view(file_data, file_size), filepath);
- return result;
+ return_if_error(read_whole_file(filepath.data, &file_content));
+ return parser_parse_buffer(self, create_buffer_view(file_content.data, file_content.size), filepath);
}
static CHECK_RESULT int file_path_join(BufferView directory, BufferView file, char **result_path) {
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index e7434f8..c4ed0d3 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -50,7 +50,8 @@ int ssa_init(Ssa *self, ScopedAllocator *allocator) {
return_if_error(buffer_init(&self->instructions, allocator));
return_if_error(hash_map_init(&self->intermediates_map, allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number));
return_if_error(buffer_init(&self->intermediates, allocator));
- return_if_error(hash_map_init(&self->strings, allocator, sizeof(SsaStringIndex), hash_compare_string, amal_hash_string));
+ return_if_error(hash_map_init(&self->strings_map, allocator, sizeof(SsaStringIndex), hash_compare_string, amal_hash_string));
+ return_if_error(buffer_init(&self->strings, allocator));
self->intermediate_counter = 0;
self->string_counter = 0;
self->reg_counter = 0;
@@ -69,7 +70,14 @@ int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
SsaNumber ssa_get_intermediate(Ssa *self, SsaIntermediateIndex index) {
SsaNumber result;
assert(index < buffer_get_size(&self->intermediates, SsaNumber));
- am_memcpy(&result, buffer_get(&self->intermediates, index, sizeof(SsaNumber)), sizeof(result));
+ am_memcpy(&result, buffer_get(&self->intermediates, index, sizeof(SsaNumber)), sizeof(SsaNumber));
+ return result;
+}
+
+BufferView ssa_get_string(Ssa *self, SsaStringIndex index) {
+ BufferView result;
+ assert(index < buffer_get_size(&self->strings, BufferView));
+ am_memcpy(&result, buffer_get(&self->strings, index, sizeof(BufferView)), sizeof(BufferView));
return result;
}
@@ -109,7 +117,7 @@ static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringI
bool exists;
assert(result_index);
- exists = hash_map_get(&self->strings, str, result_index);
+ exists = hash_map_get(&self->strings_map, str, result_index);
if(exists)
return 0;
@@ -120,7 +128,8 @@ static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringI
*result_index = self->string_counter;
++self->string_counter;
amal_log_debug("s%u = \"%.*s\"", *result_index, str.size, str.data);
- return hash_map_insert(&self->strings, str, result_index);
+ return_if_error(buffer_append(&self->strings, &str, sizeof(str)));
+ return hash_map_insert(&self->strings_map, str, result_index);
}
static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, u16 rhs) {
@@ -157,7 +166,7 @@ static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstruction ins_type, Ss
return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister)));
*result = self->reg_counter++;
self->instructions.data[index + 0] = ins_type;
- am_memcpy(self->instructions.data + index + 1, &result, sizeof(*result));
+ am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaRegister));
am_memcpy(self->instructions.data + index + 3, &lhs, sizeof(lhs));
am_memcpy(self->instructions.data + index + 5, &rhs, sizeof(rhs));
amal_log_debug("r%u = r%u %s r%u", *result, lhs, binop_type_to_string(ins_type), rhs);
@@ -199,7 +208,7 @@ int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u8)));
*result = self->func_counter++;
self->instructions.data[index + 0] = SSA_FUNC_START;
- am_memcpy(self->instructions.data + index + 1, result, sizeof(*result));
+ am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaFuncIndex));
self->instructions.data[index + 1 + sizeof(SsaFuncIndex)] = num_args;
amal_log_debug("FUNC_START f%u(%u)", *result, num_args);
return 0;
@@ -234,7 +243,7 @@ int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(func_decl)));
*result = self->reg_counter++;
self->instructions.data[index + 0] = SSA_CALL;
- am_memcpy(self->instructions.data + index + 1, result, sizeof(*result));
+ am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaRegister));
am_memcpy(self->instructions.data + index + 1 + sizeof(SsaRegister), &func_decl, sizeof(func_decl));
amal_log_debug("r%u = CALL %p", *result, func_decl);
return 0;
@@ -358,7 +367,7 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon
}
static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
- /* TODO: Implement */
+ /* TODO: Implement, and with cross field references */
(void)self;
(void)context;
return 0;
@@ -399,34 +408,59 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) {
assert(self);
#ifdef DEBUG
- if(self->resolve_data.status != AST_RESOLVED) {
+ if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_SSA_RESOLVED) {
amal_log_error("Ast type not resolved: %d", self->type);
assert(bool_false);
}
#endif
+
+ if(self->resolve_data.status == AST_SSA_RESOLVED)
+ return self->ssa_reg;
+
switch(self->type) {
case AST_NUMBER:
- return number_generate_ssa(self->value.number, context);
+ self->ssa_reg = number_generate_ssa(self->value.number, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_FUNCTION_DECL:
- return funcdecl_generate_ssa(self->value.func_decl, context);
+ self->ssa_reg = funcdecl_generate_ssa(self->value.func_decl, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_FUNCTION_CALL:
- return funccall_generate_ssa(self, context);
+ self->ssa_reg = funccall_generate_ssa(self, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_STRUCT_DECL:
- return structdecl_generate_ssa(self->value.struct_decl, context);
+ self->ssa_reg = structdecl_generate_ssa(self->value.struct_decl, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_STRUCT_FIELD:
- return structfield_generate_ssa(self->value.struct_field, context);
+ self->ssa_reg = structfield_generate_ssa(self->value.struct_field, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_LHS:
- return lhsexpr_generate_ssa(self, context);
+ self->ssa_reg = lhsexpr_generate_ssa(self, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_IMPORT:
- /* TODO: When @import(...).data syntax is added, implement the generate ssa for it */
- return 0;
+ /* TODO: Implement cross file references */
+ self->ssa_reg = 0;
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_STRING:
- return string_generate_ssa(self->value.string, context);
+ self->ssa_reg = string_generate_ssa(self->value.string, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_VARIABLE:
- return variable_generate_ssa(self->value.variable, context);
+ self->ssa_reg = variable_generate_ssa(self->value.variable, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
case AST_BINOP:
- return binop_generate_ssa(self->value.binop, context);
+ self->ssa_reg = binop_generate_ssa(self->value.binop, context);
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
}
+
return 0;
}
diff --git a/src/std/file.c b/src/std/file.c
index 7de2b6c..84f4b0c 100644
--- a/src/std/file.c
+++ b/src/std/file.c
@@ -192,11 +192,12 @@ static CHECK_RESULT int file_get_type(const char *filepath, FileType *type) {
return 0;
}
-int read_whole_file(const char *filepath, char **data, usize *size) {
+int read_whole_file(const char *filepath, Buffer *data_result) {
FileType file_type;
FILE *file;
int result;
usize bytes_read;
+ usize size;
return_if_error(file_get_type(filepath, &file_type));
if(file_type != REGULAR) {
@@ -218,24 +219,24 @@ int read_whole_file(const char *filepath, char **data, usize *size) {
goto cleanup;
}
- *size = ftell(file);
+ size = ftell(file);
result = fseek(file, 0, SEEK_SET);
if(result != 0) {
result = ferror(file);
goto cleanup;
}
- if(*size > MAX_FILE_SIZE) {
+ if(size > MAX_FILE_SIZE) {
amal_log_error("File %s is too large (larger than 48 megabytes)", filepath);
result = -1;
goto cleanup;
}
- cleanup_if_error(am_malloc(*size, (void**)data));
- bytes_read = fread(*data, 1, *size, file);
- if(bytes_read != *size) {
+ assert(data_result->capacity == 0 && data_result->size == 0);
+ cleanup_if_error(buffer_append_empty(data_result, size));
+ bytes_read = fread(data_result->data, 1, data_result->size, file);
+ if(bytes_read != size)
result = ferror(file);
- }
cleanup:
fclose(file);
diff --git a/tests/b.amal.z b/tests/b.amal.z
new file mode 100644
index 0000000..bf8e698
--- /dev/null
+++ b/tests/b.amal.z
@@ -0,0 +1,4 @@
+typedef i64 signed long long;
+typedef f64 double;
+void f0() {
+}
diff --git a/tests/io.amal.z b/tests/io.amal.z
new file mode 100644
index 0000000..bf8e698
--- /dev/null
+++ b/tests/io.amal.z
@@ -0,0 +1,4 @@
+typedef i64 signed long long;
+typedef f64 double;
+void f0() {
+}
diff --git a/tests/main.amal.z b/tests/main.amal.z
new file mode 100644
index 0000000..8095a3a
--- /dev/null
+++ b/tests/main.amal.z
@@ -0,0 +1,36 @@
+typedef i64 signed long long;
+typedef f64 double;
+void f0() {
+void f1() {
+}
+const char* r0 = "hello";
+const char* r1 = r0;
+PUSH r0 ***
+const char* r2 = "world";
+PUSH r2 ***
+i64 r3 = 356;
+PUSH r3 ***
+f64 r4 = 13.370000;
+PUSH r4 ***
+r5 = CALL 0x7f40f8002610 ***
+i64 r6 = 23232;
+i64 r7 = r6;
+i64 r8 = 30;
+r9 = r0 * r8;
+r10 = r0 + r9;
+i64 r11 = r10;
+r12 = r0 + r0;
+i64 r13 = 34;
+i64 r14 = 32;
+r15 = r13 + r14;
+i64 r16 = 2;
+r17 = r15 / r16;
+r18 = r0 * r17;
+r19 = r12 * r18;
+i64 r20 = r19;
+const char* r21 = "lole";
+PUSH r21 ***
+r22 = CALL 0x55c96755d568 ***
+}
+void f2() {
+}
diff --git a/tests/sub/a.amal.z b/tests/sub/a.amal.z
new file mode 100644
index 0000000..e0c566e
--- /dev/null
+++ b/tests/sub/a.amal.z
@@ -0,0 +1,2 @@
+typedef i64 signed long long;
+typedef f64 double;