Reproduce command
Some checks failed
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 1h30m4s
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 1h30m23s
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 1h31m28s
CI / ci (Debug, ubuntu-latest) (pull_request) Has been cancelled
CI / ci (Debug, ubuntu-latest) (push) Has started running
CI / ci (MinSizeRel, ubuntu-latest) (push) Has started running
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Has started running
CI / ci (Release, ubuntu-latest) (push) Has started running

This commit is contained in:
David Gonzalez Martin 2025-06-21 07:58:19 -06:00
parent 03aa714a51
commit aa76d7e081
4 changed files with 150 additions and 3 deletions

View File

@ -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;

View File

@ -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<Definition> 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<char* const> arguments, Slice<char* const> 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;

View File

@ -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<Definition> definitions;
Slice<String> objects;
Slice<String> library_paths;
Slice<String> library_names;

View File

@ -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);