Start preparing for C compilation

This commit is contained in:
David Gonzalez Martin 2024-06-09 08:37:28 -06:00
parent 0d87c928e8
commit a4c60754cd
5 changed files with 188 additions and 100 deletions

View File

@ -1,6 +1,7 @@
const compiler = @import("../compiler.zig"); const compiler = @import("../compiler.zig");
const LLVM = compiler.LLVM; const LLVM = compiler.LLVM;
pub extern fn NativityLLVMInitializeAll() void;
pub extern fn NativityLLVMCreateContext() *LLVM.Context; pub extern fn NativityLLVMCreateContext() *LLVM.Context;
pub extern fn NativityLLVMCreateModule(module_name_ptr: [*]const u8, module_name_len: usize, context: *LLVM.Context) *LLVM.Module; pub extern fn NativityLLVMCreateModule(module_name_ptr: [*]const u8, module_name_len: usize, context: *LLVM.Context) *LLVM.Module;
pub extern fn NativityLLVMCreateBuilder(context: *LLVM.Context) *LLVM.Builder; pub extern fn NativityLLVMCreateBuilder(context: *LLVM.Context) *LLVM.Builder;

View File

@ -3069,6 +3069,7 @@ const Job = packed struct(u64) {
llvm_optimize, llvm_optimize,
llvm_emit_object, llvm_emit_object,
llvm_notify_object_done, llvm_notify_object_done,
compile_c_source_file,
}; };
}; };
@ -3322,6 +3323,7 @@ const Unit = struct {
main_source_file_path: []const u8, main_source_file_path: []const u8,
executable_path: []const u8, executable_path: []const u8,
object_path: []const u8, object_path: []const u8,
c_source_files: []const []const u8,
target: Target, target: Target,
optimization: Optimization, optimization: Optimization,
generate_debug_information: bool, generate_debug_information: bool,
@ -3336,6 +3338,9 @@ const Unit = struct {
.descriptor = descriptor, .descriptor = descriptor,
}; };
if (descriptor.c_source_files.len > 0) {
LLVM.initializeAll();
} else {
switch (unit.descriptor.target.arch) { switch (unit.descriptor.target.arch) {
inline else => |a| { inline else => |a| {
const arch = @field(LLVM, @tagName(a)); const arch = @field(LLVM, @tagName(a));
@ -3346,24 +3351,37 @@ const Unit = struct {
arch.initializeAsmParser(); arch.initializeAsmParser();
}, },
} }
}
const main_source_file_absolute = instance.path_from_cwd(instance.arena, unit.descriptor.main_source_file_path); const main_source_file_absolute = instance.path_from_cwd(instance.arena, unit.descriptor.main_source_file_path);
const new_file_index = add_file(main_source_file_absolute, &.{}); const new_file_index = add_file(main_source_file_absolute, &.{});
instance.threads[0].task_system.program_state = .analysis; var last_assigned_thread_index: u32 = 0;
instance.threads[0].add_thread_work(Job{ instance.threads[last_assigned_thread_index].task_system.program_state = .analysis;
instance.threads[last_assigned_thread_index].add_thread_work(Job{
.offset = new_file_index, .offset = new_file_index,
.count = 1, .count = 1,
.id = .analyze_file, .id = .analyze_file,
}); });
control_thread(unit); last_assigned_thread_index += 1;
for (descriptor.c_source_files, 0..) |_, index| {
const thread_index = last_assigned_thread_index % instance.threads.len;
instance.threads[thread_index].add_thread_work(Job{
.offset = @intCast(index),
.count = 1,
.id = .compile_c_source_file,
});
last_assigned_thread_index += 1;
}
control_thread(unit, last_assigned_thread_index);
return unit; return unit;
} }
}; };
fn control_thread(unit: *Unit) void { fn control_thread(unit: *Unit, lati: u32) void {
var last_assigned_thread_index: u32 = 1; var last_assigned_thread_index: u32 = lati;
var first_ir_done = false; var first_ir_done = false;
var total_is_done: bool = false; var total_is_done: bool = false;
var iterations_without_work_done: u32 = 0; var iterations_without_work_done: u32 = 0;
@ -3613,6 +3631,7 @@ fn command_exe(arguments: []const []const u8) void {
.main_source_file_path = main_source_file_path, .main_source_file_path = main_source_file_path,
.object_path = object_path, .object_path = object_path,
.executable_path = executable_path, .executable_path = executable_path,
.c_source_files = &.{},
.optimization = optimization, .optimization = optimization,
.generate_debug_information = generate_debug_information, .generate_debug_information = generate_debug_information,
.codegen_backend = .{ .codegen_backend = .{
@ -6650,6 +6669,7 @@ fn get_array_type(thread: *Thread, descriptor: Type.Array.Descriptor) *Type {
pub const LLVM = struct { pub const LLVM = struct {
const bindings = @import("backend/llvm_bindings.zig"); const bindings = @import("backend/llvm_bindings.zig");
pub const initializeAll = bindings.NativityLLVMInitializeAll;
pub const x86_64 = struct { pub const x86_64 = struct {
pub const initializeTarget = bindings.LLVMInitializeX86Target; pub const initializeTarget = bindings.LLVMInitializeX86Target;
pub const initializeTargetInfo = bindings.LLVMInitializeX86TargetInfo; pub const initializeTargetInfo = bindings.LLVMInitializeX86TargetInfo;

View File

@ -31,32 +31,35 @@ fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const [
const bootstrap_relative_path = "zig-out/bin/nat"; const bootstrap_relative_path = "zig-out/bin/nat";
fn runStandalone(allocator: Allocator, args: struct { const Run = struct{
directory_path: []const u8, compilation_run: usize = 0,
group_name: []const u8, compilation_failure: usize = 0,
self_hosted: bool, test_run: usize = 0,
is_test: bool, test_failure: usize = 0,
compiler_path: []const u8,
fn add(run: *Run, other: Run) void {
run.compilation_run += other.compilation_run;
run.compilation_failure += other.compilation_failure;
run.test_run += other.test_run;
run.test_failure += other.test_failure;
}
};
fn compiler_run(allocator: Allocator, args: struct{
test_name: []const u8,
repetitions: usize, repetitions: usize,
}) !void { extra_arguments: []const []const u8,
const test_names = try collectDirectoryDirEntries(allocator, args.directory_path); source_file_path: []const u8,
std.debug.assert(args.repetitions > 0); compiler_path: []const u8,
is_test: bool,
self_hosted: bool,
}) !Run {
std.debug.print("{s} [repetitions={}] {s}", .{args.test_name, args.repetitions, if (args.repetitions > 1) "\n\n" else ""});
var run = Run{};
const total_compilation_count = test_names.len;
var ran_compilation_count: usize = 0;
var failed_compilation_count: usize = 0;
var ran_test_count: usize = 0;
var failed_test_count: usize = 0;
const total_test_count = test_names.len;
std.debug.print("\n[{s} START]\n\n", .{args.group_name});
for (test_names) |test_name| {
std.debug.print("{s} [repetitions={}]{s}", .{test_name, args.repetitions, if (args.repetitions > 1) "\n\n" else ""});
for (0..args.repetitions) |_| { for (0..args.repetitions) |_| {
const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" }); const base_argv: []const []const u8 = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", args.source_file_path };
const argv: []const []const u8 = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }; const argv = try std.mem.concat(allocator, []const u8, &.{base_argv, args.extra_arguments});
// if (std.mem.eql(u8, args.compiler_path, "nat/compiler_lightly_optimize_for_speed")) @breakpoint(); // if (std.mem.eql(u8, args.compiler_path, "nat/compiler_lightly_optimize_for_speed")) @breakpoint();
const compile_run = try std.process.Child.run(.{ const compile_run = try std.process.Child.run(.{
.allocator = allocator, .allocator = allocator,
@ -64,7 +67,7 @@ fn runStandalone(allocator: Allocator, args: struct {
.argv = argv, .argv = argv,
.max_output_bytes = std.math.maxInt(u64), .max_output_bytes = std.math.maxInt(u64),
}); });
ran_compilation_count += 1; run.compilation_run += 1;
const compilation_result: TestError!bool = switch (compile_run.term) { const compilation_result: TestError!bool = switch (compile_run.term) {
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
@ -74,7 +77,7 @@ fn runStandalone(allocator: Allocator, args: struct {
}; };
const compilation_success = compilation_result catch b: { const compilation_success = compilation_result catch b: {
failed_compilation_count += 1; run.compilation_failure += 1;
break :b false; break :b false;
}; };
@ -87,13 +90,13 @@ fn runStandalone(allocator: Allocator, args: struct {
} }
if (compilation_success and !args.self_hosted) { if (compilation_success and !args.self_hosted) {
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", args.test_name });
const test_run = try std.process.Child.run(.{ const test_run = try std.process.Child.run(.{
.allocator = allocator, .allocator = allocator,
.argv = &.{test_path}, .argv = &.{test_path},
.max_output_bytes = std.math.maxInt(u64), .max_output_bytes = std.math.maxInt(u64),
}); });
ran_test_count += 1; run.test_run += 1;
const test_result: TestError!bool = switch (test_run.term) { const test_result: TestError!bool = switch (test_run.term) {
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
.Signal => error.signaled, .Signal => error.signaled,
@ -102,9 +105,10 @@ fn runStandalone(allocator: Allocator, args: struct {
}; };
const test_success = test_result catch b: { const test_success = test_result catch b: {
failed_test_count += 1;
break :b false; break :b false;
}; };
run.test_failure += @intFromBool(!test_success);
std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"}); std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
if (test_run.stdout.len > 0) { if (test_run.stdout.len > 0) {
std.debug.print("STDOUT:\n\n{s}\n\n", .{test_run.stdout}); std.debug.print("STDOUT:\n\n{s}\n\n", .{test_run.stdout});
@ -116,16 +120,56 @@ fn runStandalone(allocator: Allocator, args: struct {
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} }
} }
return run;
} }
std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{ args.group_name, total_compilation_count, failed_compilation_count }); fn group_start(group: []const u8, test_count: usize) void {
std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{ args.group_name, total_test_count, ran_test_count, failed_test_count }); std.debug.print("\n[{s} START ({} tests queued)]\n\n", .{group, test_count});
}
if (failed_compilation_count > 0 or failed_test_count > 0) { fn group_end(group: []const u8, test_count: usize, run: Run) !void {
std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{ group, test_count, run.compilation_failure });
std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{ group, test_count, run.test_run, run.test_failure });
std.debug.print("\n[{s} END]\n\n", .{group});
if (run.compilation_failure > 0 or run.test_failure > 0) {
return error.fail; return error.fail;
} }
} }
fn runStandalone(allocator: Allocator, args: struct {
directory_path: []const u8,
group_name: []const u8,
self_hosted: bool,
is_test: bool,
compiler_path: []const u8,
repetitions: usize,
}) !void {
const test_names = try collectDirectoryDirEntries(allocator, args.directory_path);
std.debug.assert(args.repetitions > 0);
var total_run = Run{};
group_start(args.group_name, test_names.len * args.repetitions);
for (test_names) |test_name| {
const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" });
const run = try compiler_run(allocator, .{
.compiler_path = args.compiler_path,
.source_file_path = source_file_path,
.test_name = test_name,
.repetitions = args.repetitions,
.extra_arguments = &.{},
.is_test = args.is_test,
.self_hosted = args.self_hosted,
});
total_run.add(run);
}
try group_end(args.group_name, test_names.len * args.repetitions, total_run);
}
fn runBuildTests(allocator: Allocator, args: struct { fn runBuildTests(allocator: Allocator, args: struct {
self_hosted: bool, self_hosted: bool,
compiler_path: []const u8, compiler_path: []const u8,
@ -583,6 +627,22 @@ fn run_test_suite(allocator: Allocator, args: struct {
return errors; return errors;
} }
fn c_abi_tests(allocator: Allocator) !void {
const test_count = 1;
const group = "C ABI";
group_start(group, test_count);
const run = try compiler_run(allocator, .{
.test_name = "c_abi",
.repetitions = 1,
.extra_arguments = &.{},
.source_file_path = "retest/c_abi/main.nat",
.compiler_path = bootstrap_relative_path,
.is_test = false,
.self_hosted = false,
});
try group_end(group, test_count, run);
}
pub fn main() !void { pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena.allocator(); const allocator = arena.allocator();
@ -596,6 +656,8 @@ pub fn main() !void {
.repetitions = 1, .repetitions = 1,
}); });
try c_abi_tests(allocator);
// var errors = run_test_suite(allocator, .{ // var errors = run_test_suite(allocator, .{
// .self_hosted = false, // .self_hosted = false,
// .compiler_path = bootstrap_relative_path, // .compiler_path = bootstrap_relative_path,

4
retest/c_abi/main.nat Normal file
View File

@ -0,0 +1,4 @@
fn[cc(.c)] main[export]() s32
{
return 0;
}

View File

@ -25,6 +25,15 @@ using namespace llvm;
using llvm::orc::ThreadSafeContext; using llvm::orc::ThreadSafeContext;
using llvm::orc::ThreadSafeModule; using llvm::orc::ThreadSafeModule;
extern "C" void NativityLLVMInitializeAll()
{
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
}
extern "C" LLVMContext* NativityLLVMCreateContext() extern "C" LLVMContext* NativityLLVMCreateContext()
{ {
auto* context = new LLVMContext(); auto* context = new LLVMContext();
@ -940,14 +949,6 @@ extern "C" void NativityLLVMCallSetCallingConvention(CallBase& call_instruction,
call_instruction.setCallingConv(calling_convention); call_instruction.setCallingConv(calling_convention);
} }
extern "C" void NativityLLVMInitializeCodeGeneration()
{
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
}
extern "C" const Target* NativityLLVMGetTarget(const char* target_triple_ptr, size_t target_triple_len, const char** message_ptr, size_t* message_len) extern "C" const Target* NativityLLVMGetTarget(const char* target_triple_ptr, size_t target_triple_len, const char** message_ptr, size_t* message_len)
{ {