diff --git a/bang/src/bang.c b/bang/src/bang.c index 69a9640..2c96b48 100644 --- a/bang/src/bang.c +++ b/bang/src/bang.c @@ -9,6 +9,8 @@ // #include "./basm.h" #include "./bang_compiler.h" +#define BANG_DEFAULT_STACK_SIZE 4096 + static void build_usage(FILE *stream) { fprintf(stream, "Usage: bang build [OPTIONS] \n"); @@ -16,6 +18,7 @@ static void build_usage(FILE *stream) fprintf(stream, " -o Provide output path\n"); fprintf(stream, " -t Output target. Default is `bm`.\n"); fprintf(stream, " Provide `list` to get the list of all available targets.\n"); + fprintf(stream, " -s Local variables stack size in bytes. (default %zu)\n", (size_t) BANG_DEFAULT_STACK_SIZE); fprintf(stream, " -h Print this help to stdout\n"); } @@ -46,7 +49,11 @@ static void help_subcommand(int argc, char **argv) static void run_usage(FILE *stream) { - fprintf(stream, "Usage: bang run \n"); + fprintf(stream, "Usage: bang run [OPTIONS] \n"); + fprintf(stream, "OPTIONS:\n"); + fprintf(stream, " -t Enable trace mode\n"); + fprintf(stream, " -s Local variables stack size in bytes. (default %zu)\n", (size_t) BANG_DEFAULT_STACK_SIZE); + fprintf(stream, " -h Print this help to stdout\n"); } static void run_subcommand(int argc, char **argv) @@ -55,14 +62,45 @@ static void run_subcommand(int argc, char **argv) static Basm basm = {0}; static Bang bang = {0}; - if (argc == 0) { + bool trace = false; + const char *input_file_path = NULL; + size_t stack_size = BANG_DEFAULT_STACK_SIZE; + + while (argc > 0) { + const char *flag = shift(&argc, &argv); + if (strcmp(flag, "-t") == 0) { + trace = true; + } else if (strcmp(flag, "-h") == 0) { + run_usage(stdout); + exit(0); + } else if (strcmp(flag, "-s") == 0) { + if (argc <= 0) { + run_usage(stderr); + fprintf(stderr, "ERROR: no value is provided for flag `%s`\n", flag); + exit(1); + } + const char *stack_size_cstr = shift(&argc, &argv); + char *endptr = NULL; + + stack_size = strtoumax(stack_size_cstr, &endptr, 10); + + if (stack_size_cstr == endptr || *endptr != '\0') { + run_usage(stderr); + fprintf(stderr, "ERROR: `%s` is not a valid size of the stack\n", + stack_size_cstr); + exit(1); + } + } else { + input_file_path = flag; + } + } + + if (input_file_path == NULL) { run_usage(stderr); fprintf(stderr, "ERROR: no input file is provided\n"); exit(1); } - const char *input_file_path = shift(&argc, &argv); - String_View content = {0}; if (arena_slurp_file(&bang.arena, sv_from_cstr(input_file_path), &content) < 0) { fprintf(stderr, "ERROR: could not read file `%s`: %s", @@ -74,9 +112,9 @@ static void run_subcommand(int argc, char **argv) Bang_Module module = parse_bang_module(&basm.arena, &lexer); bang.write_id = basm_push_external_native(&basm, SV("write")); - bang_prepare_var_stack(&bang, &basm); + bang_prepare_var_stack(&bang, &basm, stack_size); - bang_push_new_scope(&bang); + bang_push_new_scope(&bang, &basm); { compile_bang_module_into_basm(&bang, &basm, module); @@ -84,7 +122,7 @@ static void run_subcommand(int argc, char **argv) bang_generate_heap_base(&bang, &basm, SV("heap_base")); assert(basm.has_entry); } - bang_pop_scope(&bang); + bang_pop_scope(&bang, &basm); basm_save_to_bm(&basm, &bm); @@ -96,12 +134,37 @@ static void run_subcommand(int argc, char **argv) } } - const int limit = -1; - Err err = bm_execute_program(&bm, limit); + while (!bm.halt) { + if (trace) { + const Inst inst = bm.program[bm.ip]; + const Inst_Def def = get_inst_def(inst.type); + fprintf(stderr, "%s", def.name); + if (def.has_operand) { + fprintf(stderr, " %"PRIu64, inst.operand.as_u64); + } + fprintf(stderr, "\n"); + } + Err err = bm_execute_inst(&bm); + if (trace) { + // TODO(#469): `bang run` needs a way to customize trace mode parameters +#define BANG_TRACE_MEMORY_START 0 +#define BANG_TRACE_CELL_COUNT 5 +#define BANG_TRACE_CELL_SIZE 8 + for (size_t cell = 0; cell < BANG_TRACE_CELL_COUNT; ++cell) { + const Memory_Addr start = BANG_TRACE_MEMORY_START + cell * BANG_TRACE_CELL_SIZE; + fprintf(stderr, " %04"PRIX64":", start); + for (size_t byte = 0; byte < BANG_TRACE_CELL_SIZE; ++byte) { + const Memory_Addr addr = start + byte; + fprintf(stderr, " %02X", bm.memory[addr]); + } + fprintf(stderr, "\n"); + } + } - if (err != ERR_OK) { - fprintf(stderr, "ERROR: %s\n", err_as_cstr(err)); - exit(1); + if (err != ERR_OK) { + fprintf(stderr, "ERROR: %s\n", err_as_cstr(err)); + exit(1); + } } } @@ -112,6 +175,7 @@ static void build_subcommand(int argc, char **argv) const char *input_file_path = NULL; const char *output_file_path = NULL; + size_t stack_size = BANG_DEFAULT_STACK_SIZE; Target output_target = TARGET_BM; while (argc > 0) { @@ -146,6 +210,23 @@ static void build_subcommand(int argc, char **argv) fprintf(stderr, "ERROR: unknown target: `%s`\n", name); exit(1); } + } else if (strcmp(flag, "-s") == 0) { + if (argc <= 0) { + build_usage(stderr); + fprintf(stderr, "ERROR: no value is provided for flag `%s`\n", flag); + exit(1); + } + const char *stack_size_cstr = shift(&argc, &argv); + char *endptr = NULL; + + stack_size = strtoumax(stack_size_cstr, &endptr, 10); + + if (stack_size_cstr == endptr || *endptr != '\0') { + build_usage(stderr); + fprintf(stderr, "ERROR: `%s` is not a valid size of the stack\n", + stack_size_cstr); + exit(1); + } } else if (strcmp(flag, "-h") == 0) { build_usage(stdout); exit(0); @@ -181,9 +262,9 @@ static void build_subcommand(int argc, char **argv) Bang_Module module = parse_bang_module(&basm.arena, &lexer); bang.write_id = basm_push_external_native(&basm, SV("write")); - bang_prepare_var_stack(&bang, &basm); + bang_prepare_var_stack(&bang, &basm, stack_size); - bang_push_new_scope(&bang); + bang_push_new_scope(&bang, &basm); { compile_bang_module_into_basm(&bang, &basm, module); @@ -192,7 +273,7 @@ static void build_subcommand(int argc, char **argv) assert(basm.has_entry); basm_save_to_file_as_target(&basm, output_file_path, output_target); } - bang_pop_scope(&bang); + bang_pop_scope(&bang, &basm); arena_free(&basm.arena); arena_free(&bang.arena); diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index d3d5160..b37cd95 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -539,7 +539,7 @@ void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) break; case BANG_STMT_KIND_VAR_DEF: - compile_stack_var_def_into_basm(bang, basm, stmt.as.var_def); + compile_stack_var_def_into_basm(bang, stmt.as.var_def); break; case COUNT_BANG_STMT_KINDS: @@ -551,12 +551,12 @@ void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) void compile_block_into_basm(Bang *bang, Basm *basm, Bang_Block *block) { - bang_push_new_scope(bang); + bang_push_new_scope(bang, basm); while (block) { compile_stmt_into_basm(bang, basm, block->stmt); block = block->next; } - bang_pop_scope(bang); + bang_pop_scope(bang, basm); } Compiled_Proc *bang_get_compiled_proc_by_name(Bang *bang, String_View name) @@ -672,14 +672,11 @@ void bang_generate_heap_base(Bang *bang, Basm *basm, String_View heap_base_var_n } } -void bang_prepare_var_stack(Bang *bang, Basm *basm) +void bang_prepare_var_stack(Bang *bang, Basm *basm, size_t stack_size) { - basm_push_byte_array_to_memory(basm, BANG_STACK_CAPACITY, 0); - const Memory_Addr stack_start_addr = BANG_STACK_CAPACITY; + basm_push_byte_array_to_memory(basm, stack_size, 0); + const Memory_Addr stack_start_addr = stack_size; - bang->stack_top_var_addr = - basm_push_buffer_to_memory( - basm, (uint8_t*) &stack_start_addr, sizeof(stack_start_addr)).as_u64; bang->stack_frame_var_addr = basm_push_buffer_to_memory( basm, (uint8_t*) &stack_start_addr, sizeof(stack_start_addr)).as_u64; @@ -721,7 +718,7 @@ void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_d bang_scope_push_var(bang->scope, new_var); } -void compile_stack_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def) +void compile_stack_var_def_into_basm(Bang *bang, Bang_Var_Def var_def) { Bang_Type type = 0; if (!bang_type_by_name(var_def.type_name, &type)) { @@ -750,19 +747,80 @@ void compile_stack_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_de exit(1); } - (void) basm; - assert(false && "TODO(#458): compiling the stack variable is not implemented"); + Bang_Type_Def type_def = bang_type_def(type); + + Compiled_Var new_var = {0}; + new_var.def = var_def; + new_var.type = type; + new_var.storage = BANG_VAR_STACK_STORAGE; + assert(type_def.size > 0); + bang->scope->frame_top_offset += type_def.size; + new_var.addr = bang->scope->frame_top_offset; + + bang_scope_push_var(bang->scope, new_var); +} + +static void compile_read_frame_addr(Bang *bang, Basm *basm) +{ + basm_push_inst(basm, INST_PUSH, word_u64(bang->stack_frame_var_addr)); + basm_push_inst(basm, INST_READ64U, word_u64(0)); +} + +static void compile_write_frame_addr(Bang *bang, Basm *basm) +{ + basm_push_inst(basm, INST_PUSH, word_u64(bang->stack_frame_var_addr)); + basm_push_inst(basm, INST_SWAP, word_u64(1)); + basm_push_inst(basm, INST_WRITE64, word_u64(0)); } -void bang_push_new_scope(Bang *bang) +static void compile_push_new_frame(Bang *bang, Basm *basm) { + // 1. read frame addr + compile_read_frame_addr(bang, basm); + + // 2. offset the frame addr to find the top of the stack + assert(bang->scope != NULL); + basm_push_inst(basm, INST_PUSH, word_u64(bang->scope->frame_top_offset)); + basm_push_inst(basm, INST_MINUSI, word_u64(0)); + + // 3. allocate memory to store the prev frame addr + // TODO(#470): get the actual size of the pointer from the definition of the ptr type + basm_push_inst(basm, INST_PUSH, word_u64(8)); + basm_push_inst(basm, INST_MINUSI, word_u64(0)); + basm_push_inst(basm, INST_DUP, word_u64(0)); + compile_read_frame_addr(bang, basm); + basm_push_inst(basm, INST_WRITE64, word_u64(0)); + + // 4. redirect the current frame + compile_write_frame_addr(bang, basm); +} + +static void compile_pop_frame(Bang *bang, Basm *basm) +{ + // 1. read frame addr + compile_read_frame_addr(bang, basm); + + // 2. read prev frame addr + basm_push_inst(basm, INST_READ64U, word_u64(0)); + + // 3. write the prev frame back to the current frame + compile_write_frame_addr(bang, basm); +} + +void bang_push_new_scope(Bang *bang, Basm *basm) +{ + if (bang->scope) { + compile_push_new_frame(bang, basm); + } + Bang_Scope *scope = arena_alloc(&bang->arena, sizeof(Bang_Scope)); scope->parent = bang->scope; bang->scope = scope; } -void bang_pop_scope(Bang *bang) +void bang_pop_scope(Bang *bang, Basm *basm) { + compile_pop_frame(bang, basm); assert(bang->scope != NULL); bang->scope = bang->scope->parent; } diff --git a/bang/src/bang_compiler.h b/bang/src/bang_compiler.h index 239eb4f..3042832 100644 --- a/bang/src/bang_compiler.h +++ b/bang/src/bang_compiler.h @@ -57,13 +57,12 @@ struct Bang_Scope { Bang_Scope *parent; Compiled_Var vars[BANG_SCOPE_VARS_CAPACITY]; size_t vars_count; + Memory_Addr frame_top_offset; }; Compiled_Var *bang_scope_get_compiled_var_by_name(Bang_Scope *scope, String_View name); void bang_scope_push_var(Bang_Scope *scope, Compiled_Var var); -#define BANG_STACK_CAPACITY 32 - #define STACK_TOP_VAR_TYPE BANG_TYPE_I64 #define STACK_FRAME_VAR_TYPE BANG_TYPE_I64 @@ -72,7 +71,6 @@ typedef struct { Native_ID write_id; - Memory_Addr stack_top_var_addr; Memory_Addr stack_frame_var_addr; Bang_Scope *scope; @@ -104,18 +102,18 @@ void compile_bang_while_into_basm(Bang *bang, Basm *basm, Bang_While hwile); void compile_bang_var_assign_into_basm(Bang *bang, Basm *basm, Bang_Var_Assign var_assign); void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module); void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); -void compile_stack_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); +void compile_stack_var_def_into_basm(Bang *bang, Bang_Var_Def var_def); Bang_Type compile_var_read_into_basm(Bang *bang, Basm *basm, Bang_Var_Read var_read); Bang_Type compile_binary_op_into_basm(Bang *bang, Basm *basm, Bang_Binary_Op binary_op); -void bang_push_new_scope(Bang *bang); -void bang_pop_scope(Bang *bang); +void bang_push_new_scope(Bang *bang, Basm *basm); +void bang_pop_scope(Bang *bang, Basm *basm); void bang_generate_entry_point(Bang *bang, Basm *basm, String_View entry_proc_name); void bang_generate_heap_base(Bang *bang, Basm *basm, String_View heap_base_var_name); void bang_funcall_expect_arity(Bang_Funcall funcall, size_t expected_arity); -void bang_prepare_var_stack(Bang *bang, Basm *basm); +void bang_prepare_var_stack(Bang *bang, Basm *basm, size_t stack_size); #endif // BANG_COMPILER_H_