From aa76d7e0817ae06a3fd709beb73a8f4338e08f69 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Sat, 21 Jun 2025 07:58:19 -0600 Subject: [PATCH] Reproduce command --- src/compiler.bbb | 92 ++++++++++++++++++++++++++++++++++++++++++++++-- src/compiler.cpp | 53 +++++++++++++++++++++++++++- src/compiler.hpp | 7 ++++ src/parser.cpp | 1 + 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index e1099b8..620797f 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -984,6 +984,7 @@ CompilerCommand = enum { compile, test, + reproduce, } BuildMode = enum @@ -1044,12 +1045,19 @@ target_compare = fn (a: Target, b: Target) u1 return is_same_cpu and is_same_os; } +Definition = struct +{ + name: []u8, + value: []u8, +} + CompileOptions = struct { content: []u8, path: []u8, executable: []u8, name: []u8, + definitions: []Definition, objects: [][]u8, library_directories: [][]u8, library_names: [][]u8, @@ -18200,6 +18208,38 @@ compile = fn (arena: &Arena, options: CompileOptions) void module.scope.types.first = base_type_allocation; module.scope.types.last = noreturn_type; + for (&definition: options.definitions) + { + >definition_global = new_global(&module); + >definition_value = new_value(&module); + >definition_storage = new_value(&module); + + definition_value.& = { + .content = { + .string_literal = definition.value, + }, + .id = .string_literal, + zero, + }; + + definition_storage.& = { + .id = .global, + zero, + }; + + definition_global.& = { + .variable = { + .storage = definition_storage, + .type = get_slice_type(&module, uint8(&module)), + .scope = &module.scope, + .name = definition.name, + zero, + }, + .initial_value = definition_value, + zero, + }; + } + parse(&module); emit(&module); } @@ -18268,6 +18308,12 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8 >file_path = path_absolute(arena, relative_file_path.pointer); >c_abi_object_path = ""; // TODO + >definitions: []Definition = zero; + >cmake_prefix_path_definition: Definition = { + .name = "CMAKE_PREFIX_PATH", + .value = CMAKE_PREFIX_PATH, + }; + >objects = [ output_object_path ][..]; >c_abi_library = "build/libc_abi.a"; >llvm_bindings_library = "build/libllvm_bindings.a"; @@ -18281,9 +18327,11 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8 if (is_compiler) { + definitions = { .pointer = &cmake_prefix_path_definition, .length = 1 }; + >builder: ArgumentBuilder = zero; - add_argument(&builder, "/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release/bin/llvm-config"); + add_argument(&builder, arena_join_string(arena, [ CMAKE_PREFIX_PATH, "/bin/llvm-config"][..])); add_argument(&builder, "--libdir"); add_argument(&builder, "--libs"); add_argument(&builder, "--system-libs"); @@ -18396,6 +18444,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8 >options: CompileOptions = { .executable = output_executable_path, + .definitions = definitions, .objects = objects, .library_directories = library_directories, .library_names = library_names, @@ -18558,7 +18607,10 @@ names: [_][]u8 = return 1; } + >debug_info_array: [_]u1 = [1, 0]; + >command = command_string_to_enum.enum_value; + switch (command) { .compile => @@ -18620,7 +18672,6 @@ names: [_][]u8 = report_error(); } - >debug_info_array: [_]u1 = [1, 0]; for (name: names) { for (build_mode: #enum_values(BuildMode)) @@ -18656,6 +18707,43 @@ names: [_][]u8 = } } }, + .reproduce => + { + for (build_mode: #enum_values(BuildMode)) + { + for (has_debug_info: debug_info_array) + { + >position = arena.position; + + // Produce the compiler + >relative_file_path = "src/compiler.bbb"; + >executable_path = compile_file(arena, { + .relative_file_path = relative_file_path, + .build_mode = build_mode, + .has_debug_info = has_debug_info, + .silent = 1, + }, envp); + + // Test the compiler + >arguments: [_]&u8 = [ + executable_path.pointer, + "test", + zero, + ]; + >args = arguments[..arguments.length - 1]; + >execution = os_execute(arena, args, envp, zero); + + >success = execution.termination_kind == .exit and execution.termination_code == 0; + + if (!success) + { + #trap(); + } + + arena.position = position; + } + } + }, } return 0; diff --git a/src/compiler.cpp b/src/compiler.cpp index 8ba2702..95094b3 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -109,6 +109,29 @@ fn void compile(Arena* arena, Options options) .id = ValueId::infer_or_ignore, }; + for (auto definition: options.definitions) + { + auto definition_global = new_global(&module); + auto definition_value = new_value(&module); + auto definition_storage = new_value(&module); + *definition_value = { + .string_literal = definition.value, + .id = ValueId::string_literal, + }; + *definition_storage = { + .id = ValueId::global, + }; + *definition_global = Global{ + .variable = { + .storage = definition_storage, + .initial_value = definition_value, + .type = get_slice_type(&module, uint8(&module)), + .scope = &module.scope, + .name = definition.name, + }, + }; + } + parse(&module); emit(&module); } @@ -174,6 +197,13 @@ fn String compile_file(Arena* arena, Compile options) auto file_content = file_read(arena, relative_file_path); auto file_path = path_absolute(arena, relative_file_path); + Slice definitions = {}; + auto cmake_prefix_path = string_literal(CMAKE_PREFIX_PATH); + auto cmake_prefix_path_definition = Definition{ + .name = string_literal("CMAKE_PREFIX_PATH"), + .value = cmake_prefix_path, + }; + String objects[] = { output_object_path, }; @@ -190,9 +220,11 @@ fn String compile_file(Arena* arena, Compile options) if (is_compiler) { + definitions = { .pointer = &cmake_prefix_path_definition, .length = 1 }; + ArgBuilder builder = {}; String llvm_config_parts[] = { - string_literal(CMAKE_PREFIX_PATH), + cmake_prefix_path, string_literal("/bin/llvm-config"), }; builder.add(arena, arena_join_string(arena, array_to_slice(llvm_config_parts))); @@ -300,6 +332,7 @@ fn String compile_file(Arena* arena, Compile options) .path = file_path, .executable = output_executable_path, .name = base_name, + .definitions = definitions, .objects = object_slice, .library_paths = library_paths, .library_names = library_names, @@ -619,6 +652,24 @@ void entry_point(Slice arguments, Slice envp) print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n")); bb_fail(); } + + char* const reproduce_arguments[] = + { + (char*)compiler.pointer, + (char*)"reproduce", + 0, + }; + arg_slice = array_to_slice(reproduce_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 reproduction failed: ")); + print(build_mode_to_string(compiler_build_mode)); + print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n")); + bb_fail(); + } } } } break; diff --git a/src/compiler.hpp b/src/compiler.hpp index c11bb2e..56962e0 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -1296,6 +1296,12 @@ struct ModuleLLVM u32 debug_tag; }; +struct Definition +{ + String name; + String value; +}; + struct Module { Arena* arena; @@ -1408,6 +1414,7 @@ struct Options String path; String executable; String name; + Slice definitions; Slice objects; Slice library_paths; Slice library_names; diff --git a/src/parser.cpp b/src/parser.cpp index 1eca489..e750513 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3166,6 +3166,7 @@ fn Block* parse_block(Module* module, Scope* parent_scope) void parse(Module* module) { auto scope = &module->scope; + while (1) { skip_space(module);