From 3eca360dbeafd25d6c00669e897784ab5b06e396 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Thu, 5 Jun 2025 04:42:39 -0600 Subject: [PATCH] build_mode, has_debug_info and self-hosted test --- src/compiler.bbb | 14 ++++++++-- src/compiler.cpp | 60 ++++++++++++++++++++++++++++++++-------- src/compiler.hpp | 12 +++++++- src/emitter.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.cpp | 15 ++++++++-- 5 files changed, 156 insertions(+), 16 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index b6dda3d..86f1da5 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -5449,8 +5449,15 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void >base_name = relative_file_path[base_start..extension_start]; >is_compiler = string_equal(relative_file_path, "src/compiler.bbb"); - >outputh_path_dir = arena_join_string(arena, [ + >base_dir = arena_join_string(arena, [ base_cache_dir, + "/", + #enum_name(#build_mode), + "_", + #select(#has_debug_info(), "di", "nodi"), + ][..]); + >outputh_path_dir = arena_join_string(arena, [ + base_dir, #select(is_compiler, "/compiler/", "/"), #enum_name(compile_options.build_mode), "_", @@ -5458,11 +5465,14 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void ][..]); os_make_directory(base_cache_dir.pointer); + os_make_directory(base_dir.pointer); + if (is_compiler) { - >compiler_dir = arena_join_string(arena, [ base_cache_dir, "/compiler" ][..]); + >compiler_dir = arena_join_string(arena, [ base_dir, "/compiler" ][..]); os_make_directory(compiler_dir.pointer); } + os_make_directory(outputh_path_dir.pointer); >outputh_path_base = arena_join_string(arena, [ outputh_path_dir, "/", base_name ][..]); diff --git a/src/compiler.cpp b/src/compiler.cpp index 625dc05..5aaa999 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -588,24 +588,27 @@ void entry_point(Slice arguments, Slice envp) } } - for (BuildMode build_mode = BuildMode::debug_none; build_mode < BuildMode::count; build_mode = (BuildMode)((backing_type(BuildMode))build_mode + 1)) + for (BuildMode compiler_build_mode = BuildMode::debug_none; compiler_build_mode < BuildMode::count; compiler_build_mode = (BuildMode)((backing_type(BuildMode))compiler_build_mode + 1)) { - for (bool has_debug_info : has_debug_info_array) + for (bool compiler_has_debug_info : has_debug_info_array) { auto compiler = compile_file(arena, { - .relative_file_path = string_literal("src/compiler.bbb"), - .build_mode = build_mode, - .has_debug_info = has_debug_info, - .silent = true, - }); + .relative_file_path = string_literal("src/compiler.bbb"), + .build_mode = compiler_build_mode, + .has_debug_info = compiler_has_debug_info, + .silent = true, + }); - for (auto name: names) + Slice name_slice = array_to_slice(names); + for (auto name: name_slice(0, 1)) { + // COMPILATION START + BuildMode build_mode = BuildMode::debug_none; bool has_debug_info = true; String relative_file_path_parts[] = { string_literal("tests/"), name, string_literal(".bbb") }; auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts)); - char* const arguments[] = + char* const compiler_arguments[] = { (char*)compiler.pointer, (char*)"compile", @@ -614,7 +617,7 @@ void entry_point(Slice arguments, Slice envp) (char*)(has_debug_info ? "true" : "false"), 0, }; - Slice arg_slice = array_to_slice(arguments); + Slice arg_slice = array_to_slice(compiler_arguments); arg_slice.length -= 1; auto execution = os_execute(arena, arg_slice, environment, {}); auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0; @@ -625,7 +628,42 @@ void entry_point(Slice arguments, Slice envp) print(string_literal("\n")); bb_fail(); } - break; + + // COMPILATION END + + // RUN START + + String exe_parts[] = { + string_literal("self-hosted-bb-cache/"), + build_mode_to_string(compiler_build_mode), + string_literal("_"), + compiler_has_debug_info ? string_literal("di") : string_literal("nodi"), + string_literal("/"), + build_mode_to_string(build_mode), + string_literal("_"), + has_debug_info ? string_literal("di") : string_literal("nodi"), + string_literal("/"), + name, + }; + String exe_path = arena_join_string(arena, array_to_slice(exe_parts)); + char* const run_arguments[] = + { + (char*)exe_path.pointer, + 0, + }; + arg_slice = array_to_slice(run_arguments); + arg_slice.length -= 1; + execution = os_execute(arena, arg_slice, environment, {}); + success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0; + if (!success) + { + print(string_literal("Self-hosted test failed to run: ")); + print(name); + print(string_literal("\n")); + bb_fail(); + } + + // RUN END } } } diff --git a/src/compiler.hpp b/src/compiler.hpp index 6c6fe86..a530d94 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -336,7 +336,7 @@ enum class TypeId struct TypeInteger { - u32 bit_count; + u64 bit_count; bool is_signed; }; @@ -840,6 +840,8 @@ enum class ValueId string_to_enum, local, argument, + build_mode, + has_debug_info, }; struct ValueConstantInteger @@ -1293,6 +1295,7 @@ struct Module Type* first_function_type; Type* va_list_type; + Type* build_mode_enum; Value* void_value; Global* first_global; @@ -2037,6 +2040,13 @@ fn Type* resolve_alias(Module* module, Type* type) } +fn u64 enum_bit_count(u64 highest_value) +{ + auto needed_bit_count = 64 - (u64)clz(highest_value); + needed_bit_count = needed_bit_count ? needed_bit_count : 1; + return needed_bit_count; +} + struct ArgBuilder { char* args[128]; diff --git a/src/emitter.cpp b/src/emitter.cpp index 4061b6e..7604d89 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -2609,6 +2609,52 @@ fn void copy_block(Module* module, Scope* parent_scope, BlockCopy copy) } } +fn Type* get_build_mode_enum(Module* module) +{ + auto result = module->build_mode_enum; + + if (!result) + { + String enum_names[] = { + string_literal("debug_none"), + string_literal("debug"), + string_literal("soft_optimize"), + string_literal("optimize_for_speed"), + string_literal("optimize_for_size"), + string_literal("aggressively_optimize_for_speed"), + string_literal("aggressively_optimize_for_size"), + }; + + auto enum_fields = arena_allocate(module->arena, array_length(enum_names)); + + u64 field_value = 0; + for (String enum_name : enum_names) + { + enum_fields[field_value] = { + .name = enum_name, + .value = field_value, + }; + + field_value += 1; + } + + auto backing_type = integer_type(module, { .bit_count = array_length(enum_names) - 1, .is_signed = false }); + + result = type_allocate_init(module, { + .enumerator = { + .fields = enum_fields, + .backing_type = backing_type, + }, + .id = TypeId::enumerator, + .name = string_literal("BuildMode"), + .scope = &module->scope, + }); + } + + assert(result); + return result; +} + fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis) { assert(!value->type); @@ -2829,6 +2875,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal typecheck(module, expected_type, string_type); analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto enum_type = unary_value->type; + resolve_type_in_place(module, enum_type); if (enum_type->id != TypeId::enumerator) { report_error(); @@ -4341,6 +4388,22 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal module->current_macro_instantiation = current_macro_instantiation; module->current_function = current_function; } break; + case ValueId::build_mode: + { + value_type = get_build_mode_enum(module); + if (expected_type) + { + // typecheck(module, expected_type); + trap(); + } + + typecheck(module, expected_type, value_type); + } break; + case ValueId::has_debug_info: + { + value_type = uint1(module); + typecheck(module, expected_type, value_type); + } break; default: unreachable(); } @@ -7646,6 +7709,14 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect { llvm_value = LLVMGetPoison(get_llvm_type(resolved_value_type, type_kind)); } break; + case ValueId::build_mode: + { + llvm_value = LLVMConstInt(get_llvm_type(resolved_value_type->enumerator.backing_type, type_kind), (u64)module->build_mode, false); + } break; + case ValueId::has_debug_info: + { + llvm_value = LLVMConstInt(get_llvm_type(resolved_value_type, type_kind), module->has_debug_info, false); + } break; default: unreachable(); } diff --git a/src/parser.cpp b/src/parser.cpp index 9f97707..69cfd2d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3,10 +3,12 @@ enum class ValueIntrinsic { align_of, + build_mode, byte_size, enum_from_int, enum_name, extend, + has_debug_info, integer_max, int_from_enum, int_from_pointer, @@ -1153,10 +1155,12 @@ fn Token tokenize(Module* module) String value_intrinsics[] = { string_literal("align_of"), + string_literal("build_mode"), string_literal("byte_size"), string_literal("enum_from_int"), string_literal("enum_name"), string_literal("extend"), + string_literal("has_debug_info"), string_literal("integer_max"), string_literal("int_from_enum"), string_literal("int_from_pointer"), @@ -1790,6 +1794,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder) } break; case ValueIntrinsic::trap: case ValueIntrinsic::va_start: + case ValueIntrinsic::has_debug_info: { skip_space(module); expect_character(module, left_parenthesis); @@ -1801,6 +1806,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder) { case ValueIntrinsic::trap: id = ValueId::trap; break; case ValueIntrinsic::va_start: id = ValueId::va_start; break; + case ValueIntrinsic::has_debug_info: id = ValueId::has_debug_info; break; default: unreachable(); } *result = { @@ -1862,6 +1868,12 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder) .id = ValueId::binary, }; } break; + case ValueIntrinsic::build_mode: + { + *result = { + .id = ValueId::build_mode, + }; + } break; case ValueIntrinsic::count: unreachable(); } } break; @@ -3477,8 +3489,7 @@ void parse(Module* module) }; } - auto needed_bit_count = 64 - (u32)clz(highest_value); - needed_bit_count = needed_bit_count ? needed_bit_count : 1; + auto needed_bit_count = enum_bit_count(highest_value); if (!backing_type) {