Compile the compiler test

This commit is contained in:
David Gonzalez Martin 2025-03-02 20:12:00 -06:00
parent bc65985a30
commit 41e566a64f
4 changed files with 285 additions and 185 deletions

View File

@ -2751,6 +2751,9 @@ fn llvm_emit_function_site_attributes(module: *Module, value: *Value) void {
}
pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
const build_dir = "bb-cache";
os.make_directory(build_dir);
var converter = Converter{
.content = options.content,
.offset = 0,

View File

@ -23,21 +23,88 @@ fn invoke(name: []const u8) !void {
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
const build_mode = @field(BuildMode, f.name);
inline for ([2]bool{ false, true }) |has_debug_info| {
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
const executable_path = base_path;
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
.executable_path = executable_path,
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
.name = name,
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
});
// Bootstrap
{
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
const executable_path = base_path;
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
.executable_path = executable_path,
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
.name = name,
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = null,
});
}
// Self-hosted
{
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
const executable_path = base_path;
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
.executable_path = executable_path,
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
.name = name,
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) }),
});
}
}
}
}
fn compiler_basename(arena: *Arena, build_mode: BuildMode, has_debug_info: bool) [:0]const u8 {
return arena.join_string(&.{ "compiler_", @tagName(build_mode), if (has_debug_info) "_di" else "_nodi" });
}
var compiler_compiled = false;
fn compile_the_compiler() !void {
if (!compiler_compiled) {
defer compiler_compiled = true;
if (!lib.GlobalState.initialized) {
lib.GlobalState.initialize();
}
comptime assert(lib.is_test);
const allocator = std.testing.allocator;
const arena = lib.global.arena;
const arena_position = arena.position;
defer arena.restore(arena_position);
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
const build_mode = @field(BuildMode, f.name);
inline for ([2]bool{ false, true }) |has_debug_info| {
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) });
const executable_path = base_path;
const directory_path = "bb-cache";
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = &.{object_path},
.executable_path = executable_path,
.file_path = arena.join_string(&.{"src/compiler.bbb"}),
.name = "compiler",
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = null,
});
}
}
}
}
@ -50,44 +117,67 @@ const InvokeWrapper = struct {
build_mode: BuildMode,
has_debug_info: bool,
directory_path: [:0]const u8,
self_hosted_path: ?[]const u8,
};
fn unit_test(arena: *Arena, allocator: std.mem.Allocator, options: InvokeWrapper) !void {
fn unit_test(arena: *Arena, allocator: std.mem.Allocator, options: InvokeWrapper) anyerror!void {
const position = arena.position;
defer arena.restore(position);
const file_content = lib.file.read(arena, options.file_path);
converter.convert(arena, .{
.path = options.file_path,
.content = file_content,
.objects = options.object_paths,
.executable = options.executable_path,
.build_mode = options.build_mode,
.name = options.name,
.has_debug_info = options.has_debug_info,
.target = converter.Target.get_native(),
});
const run_result = std.process.Child.run(.{
.allocator = allocator,
.argv = &.{options.executable_path},
}) catch |err| {
std.debug.print("error: {}\n", .{err});
const r = try std.process.Child.run(.{
if (options.self_hosted_path) |self_hosted_path| {
try compile_the_compiler();
const run_result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
.max_output_bytes = std.math.maxInt(usize),
.argv = &.{
self_hosted_path,
options.file_path,
},
});
defer allocator.free(r.stdout);
defer allocator.free(r.stderr);
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
return err;
};
const success = switch (run_result.term) {
.Exited => |exit_code| exit_code == 0,
else => false,
};
if (!success) {
std.debug.print("{}\n{}\n", .{ run_result, options });
return error.compiler_failed_to_run_successfully;
}
} else {
converter.convert(arena, .{
.path = options.file_path,
.content = file_content,
.objects = options.object_paths,
.executable = options.executable_path,
.build_mode = options.build_mode,
.name = options.name,
.has_debug_info = options.has_debug_info,
.target = converter.Target.get_native(),
});
const run_result = std.process.Child.run(.{
.allocator = allocator,
.argv = &.{options.executable_path},
}) catch |err| {
std.debug.print("error: {}\n", .{err});
const r = try std.process.Child.run(.{
.allocator = allocator,
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
.max_output_bytes = std.math.maxInt(usize),
});
defer allocator.free(r.stdout);
defer allocator.free(r.stderr);
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
return err;
};
const success = switch (run_result.term) {
.Exited => |exit_code| exit_code == 0,
else => false,
};
if (!success) {
std.debug.print("{}\n{}\n", .{ run_result, options });
return error.executable_failed_to_run_successfully;
const success = switch (run_result.term) {
.Exited => |exit_code| exit_code == 0,
else => false,
};
if (!success) {
std.debug.print("{}\n{}\n", .{ run_result, options });
return error.executable_failed_to_run_successfully;
}
}
}

View File

@ -515,7 +515,10 @@ pub const os = struct {
if (os.is_being_debugged()) {
@trap();
} else {
libc.exit(1);
switch (is_test) {
true => @panic("aborting"),
false => libc.exit(1),
}
}
}
@ -2668,3 +2671,144 @@ pub fn print_string_stdout(str: []const u8) void {
pub fn print_string_stderr(str: []const u8) void {
os.get_stderr().write(str);
}
pub const panic_struct = switch (is_test) {
true => @import("std").debug.FullPanic(@import("std").debug.defaultPanic),
false => struct {
const abort = os.abort;
pub fn call(_: []const u8, _: ?usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
@branchHint(.cold);
abort();
}
pub fn unwrapError(_: anyerror) noreturn {
@branchHint(.cold);
abort();
}
pub fn outOfBounds(_: usize, _: usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
@branchHint(.cold);
abort();
}
pub fn reachedUnreachable() noreturn {
@branchHint(.cold);
abort();
}
pub fn unwrapNull() noreturn {
@branchHint(.cold);
abort();
}
pub fn castToNull() noreturn {
@branchHint(.cold);
abort();
}
pub fn incorrectAlignment() noreturn {
@branchHint(.cold);
abort();
}
pub fn invalidErrorCode() noreturn {
@branchHint(.cold);
abort();
}
pub fn castTruncatedData() noreturn {
@branchHint(.cold);
abort();
}
pub fn negativeToUnsigned() noreturn {
@branchHint(.cold);
abort();
}
pub fn integerOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn shlOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn shrOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn divideByZero() noreturn {
@branchHint(.cold);
abort();
}
pub fn exactDivisionRemainder() noreturn {
@branchHint(.cold);
abort();
}
pub fn integerPartOutOfBounds() noreturn {
@branchHint(.cold);
abort();
}
pub fn corruptSwitch() noreturn {
@branchHint(.cold);
abort();
}
pub fn shiftRhsTooBig() noreturn {
@branchHint(.cold);
abort();
}
pub fn invalidEnumValue() noreturn {
@branchHint(.cold);
abort();
}
pub fn forLenMismatch() noreturn {
@branchHint(.cold);
abort();
}
pub fn memcpyLenMismatch() noreturn {
@branchHint(.cold);
abort();
}
pub fn memcpyAlias() noreturn {
@branchHint(.cold);
abort();
}
pub fn noreturnReturned() noreturn {
@branchHint(.cold);
abort();
}
pub fn sliceCastLenRemainder(_: usize) noreturn {
@branchHint(.cold);
abort();
}
},
};

View File

@ -5,143 +5,7 @@ const llvm = @import("LLVM.zig");
const converter = @import("converter.zig");
const Arena = lib.Arena;
pub const panic = struct {
const abort = lib.os.abort;
pub fn call(_: []const u8, _: ?usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
@branchHint(.cold);
abort();
}
pub fn unwrapError(_: anyerror) noreturn {
@branchHint(.cold);
abort();
}
pub fn outOfBounds(_: usize, _: usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
@branchHint(.cold);
abort();
}
pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
@branchHint(.cold);
abort();
}
pub fn reachedUnreachable() noreturn {
@branchHint(.cold);
abort();
}
pub fn unwrapNull() noreturn {
@branchHint(.cold);
abort();
}
pub fn castToNull() noreturn {
@branchHint(.cold);
abort();
}
pub fn incorrectAlignment() noreturn {
@branchHint(.cold);
abort();
}
pub fn invalidErrorCode() noreturn {
@branchHint(.cold);
abort();
}
pub fn castTruncatedData() noreturn {
@branchHint(.cold);
abort();
}
pub fn negativeToUnsigned() noreturn {
@branchHint(.cold);
abort();
}
pub fn integerOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn shlOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn shrOverflow() noreturn {
@branchHint(.cold);
abort();
}
pub fn divideByZero() noreturn {
@branchHint(.cold);
abort();
}
pub fn exactDivisionRemainder() noreturn {
@branchHint(.cold);
abort();
}
pub fn integerPartOutOfBounds() noreturn {
@branchHint(.cold);
abort();
}
pub fn corruptSwitch() noreturn {
@branchHint(.cold);
abort();
}
pub fn shiftRhsTooBig() noreturn {
@branchHint(.cold);
abort();
}
pub fn invalidEnumValue() noreturn {
@branchHint(.cold);
abort();
}
pub fn forLenMismatch() noreturn {
@branchHint(.cold);
abort();
}
pub fn memcpyLenMismatch() noreturn {
@branchHint(.cold);
abort();
}
pub fn memcpyAlias() noreturn {
@branchHint(.cold);
abort();
}
pub fn noreturnReturned() noreturn {
@branchHint(.cold);
abort();
}
pub fn sliceCastLenRemainder(_: usize) noreturn {
@branchHint(.cold);
abort();
}
};
pub const panic = lib.panic_struct;
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
if (argc != 2) {
@ -167,7 +31,6 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
const arena = lib.global.arena;
const build_dir = "bb-cache";
os.make_directory(build_dir);
const output_path_base = arena.join_string(&.{ build_dir, "/", base_name, "_", @tagName(lib.optimization_mode) });
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
const output_executable_path = output_path_base;