Start preparing for C compilation
This commit is contained in:
parent
0d87c928e8
commit
a4c60754cd
@ -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;
|
||||||
|
@ -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,34 +3338,50 @@ const Unit = struct {
|
|||||||
.descriptor = descriptor,
|
.descriptor = descriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (unit.descriptor.target.arch) {
|
if (descriptor.c_source_files.len > 0) {
|
||||||
inline else => |a| {
|
LLVM.initializeAll();
|
||||||
const arch = @field(LLVM, @tagName(a));
|
} else {
|
||||||
arch.initializeTarget();
|
switch (unit.descriptor.target.arch) {
|
||||||
arch.initializeTargetInfo();
|
inline else => |a| {
|
||||||
arch.initializeTargetMC();
|
const arch = @field(LLVM, @tagName(a));
|
||||||
arch.initializeAsmPrinter();
|
arch.initializeTarget();
|
||||||
arch.initializeAsmParser();
|
arch.initializeTargetInfo();
|
||||||
},
|
arch.initializeTargetMC();
|
||||||
|
arch.initializeAsmPrinter();
|
||||||
|
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;
|
||||||
|
@ -31,6 +31,113 @@ fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const [
|
|||||||
|
|
||||||
const bootstrap_relative_path = "zig-out/bin/nat";
|
const bootstrap_relative_path = "zig-out/bin/nat";
|
||||||
|
|
||||||
|
const Run = struct{
|
||||||
|
compilation_run: usize = 0,
|
||||||
|
compilation_failure: usize = 0,
|
||||||
|
test_run: usize = 0,
|
||||||
|
test_failure: usize = 0,
|
||||||
|
|
||||||
|
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,
|
||||||
|
extra_arguments: []const []const u8,
|
||||||
|
source_file_path: []const u8,
|
||||||
|
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{};
|
||||||
|
|
||||||
|
for (0..args.repetitions) |_| {
|
||||||
|
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 = 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();
|
||||||
|
const compile_run = try std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
// TODO: delete -main_source_file?
|
||||||
|
.argv = argv,
|
||||||
|
.max_output_bytes = std.math.maxInt(u64),
|
||||||
|
});
|
||||||
|
run.compilation_run += 1;
|
||||||
|
|
||||||
|
const compilation_result: TestError!bool = switch (compile_run.term) {
|
||||||
|
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
||||||
|
.Signal => error.signaled,
|
||||||
|
.Stopped => error.stopped,
|
||||||
|
.Unknown => error.unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
const compilation_success = compilation_result catch b: {
|
||||||
|
run.compilation_failure += 1;
|
||||||
|
break :b false;
|
||||||
|
};
|
||||||
|
|
||||||
|
std.debug.print("[COMPILATION {s}] ", .{if (compilation_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
||||||
|
if (compile_run.stdout.len > 0) {
|
||||||
|
std.debug.print("STDOUT:\n\n{s}\n\n", .{compile_run.stdout});
|
||||||
|
}
|
||||||
|
if (compile_run.stderr.len > 0) {
|
||||||
|
std.debug.print("STDERR:\n\n{s}\n\n", .{compile_run.stderr});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compilation_success and !args.self_hosted) {
|
||||||
|
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", args.test_name });
|
||||||
|
const test_run = try std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{test_path},
|
||||||
|
.max_output_bytes = std.math.maxInt(u64),
|
||||||
|
});
|
||||||
|
run.test_run += 1;
|
||||||
|
const test_result: TestError!bool = switch (test_run.term) {
|
||||||
|
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
||||||
|
.Signal => error.signaled,
|
||||||
|
.Stopped => error.stopped,
|
||||||
|
.Unknown => error.unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
const test_success = test_result catch b: {
|
||||||
|
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"});
|
||||||
|
if (test_run.stdout.len > 0) {
|
||||||
|
std.debug.print("STDOUT:\n\n{s}\n\n", .{test_run.stdout});
|
||||||
|
}
|
||||||
|
if (test_run.stderr.len > 0) {
|
||||||
|
std.debug.print("STDERR:\n\n{s}\n\n", .{test_run.stderr});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return run;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_start(group: []const u8, test_count: usize) void {
|
||||||
|
std.debug.print("\n[{s} START ({} tests queued)]\n\n", .{group, test_count});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn runStandalone(allocator: Allocator, args: struct {
|
fn runStandalone(allocator: Allocator, args: struct {
|
||||||
directory_path: []const u8,
|
directory_path: []const u8,
|
||||||
group_name: []const u8,
|
group_name: []const u8,
|
||||||
@ -42,88 +149,25 @@ fn runStandalone(allocator: Allocator, args: struct {
|
|||||||
const test_names = try collectDirectoryDirEntries(allocator, args.directory_path);
|
const test_names = try collectDirectoryDirEntries(allocator, args.directory_path);
|
||||||
std.debug.assert(args.repetitions > 0);
|
std.debug.assert(args.repetitions > 0);
|
||||||
|
|
||||||
const total_compilation_count = test_names.len;
|
var total_run = Run{};
|
||||||
var ran_compilation_count: usize = 0;
|
|
||||||
var failed_compilation_count: usize = 0;
|
|
||||||
|
|
||||||
var ran_test_count: usize = 0;
|
group_start(args.group_name, test_names.len * args.repetitions);
|
||||||
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| {
|
for (test_names) |test_name| {
|
||||||
std.debug.print("{s} [repetitions={}]{s}", .{test_name, args.repetitions, if (args.repetitions > 1) "\n\n" else ""});
|
const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" });
|
||||||
for (0..args.repetitions) |_| {
|
const run = try compiler_run(allocator, .{
|
||||||
const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" });
|
.compiler_path = args.compiler_path,
|
||||||
const argv: []const []const u8 = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path };
|
.source_file_path = source_file_path,
|
||||||
// if (std.mem.eql(u8, args.compiler_path, "nat/compiler_lightly_optimize_for_speed")) @breakpoint();
|
.test_name = test_name,
|
||||||
const compile_run = try std.process.Child.run(.{
|
.repetitions = args.repetitions,
|
||||||
.allocator = allocator,
|
.extra_arguments = &.{},
|
||||||
// TODO: delete -main_source_file?
|
.is_test = args.is_test,
|
||||||
.argv = argv,
|
.self_hosted = args.self_hosted,
|
||||||
.max_output_bytes = std.math.maxInt(u64),
|
});
|
||||||
});
|
total_run.add(run);
|
||||||
ran_compilation_count += 1;
|
|
||||||
|
|
||||||
const compilation_result: TestError!bool = switch (compile_run.term) {
|
|
||||||
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
|
||||||
.Signal => error.signaled,
|
|
||||||
.Stopped => error.stopped,
|
|
||||||
.Unknown => error.unknown,
|
|
||||||
};
|
|
||||||
|
|
||||||
const compilation_success = compilation_result catch b: {
|
|
||||||
failed_compilation_count += 1;
|
|
||||||
break :b false;
|
|
||||||
};
|
|
||||||
|
|
||||||
std.debug.print("[COMPILATION {s}] ", .{if (compilation_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
|
||||||
if (compile_run.stdout.len > 0) {
|
|
||||||
std.debug.print("STDOUT:\n\n{s}\n\n", .{compile_run.stdout});
|
|
||||||
}
|
|
||||||
if (compile_run.stderr.len > 0) {
|
|
||||||
std.debug.print("STDERR:\n\n{s}\n\n", .{compile_run.stderr});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compilation_success and !args.self_hosted) {
|
|
||||||
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name });
|
|
||||||
const test_run = try std.process.Child.run(.{
|
|
||||||
.allocator = allocator,
|
|
||||||
.argv = &.{test_path},
|
|
||||||
.max_output_bytes = std.math.maxInt(u64),
|
|
||||||
});
|
|
||||||
ran_test_count += 1;
|
|
||||||
const test_result: TestError!bool = switch (test_run.term) {
|
|
||||||
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
|
||||||
.Signal => error.signaled,
|
|
||||||
.Stopped => error.stopped,
|
|
||||||
.Unknown => error.unknown,
|
|
||||||
};
|
|
||||||
|
|
||||||
const test_success = test_result catch b: {
|
|
||||||
failed_test_count += 1;
|
|
||||||
break :b false;
|
|
||||||
};
|
|
||||||
std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
|
||||||
if (test_run.stdout.len > 0) {
|
|
||||||
std.debug.print("STDOUT:\n\n{s}\n\n", .{test_run.stdout});
|
|
||||||
}
|
|
||||||
if (test_run.stderr.len > 0) {
|
|
||||||
std.debug.print("STDERR:\n\n{s}\n\n", .{test_run.stderr});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std.debug.print("\n", .{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{ args.group_name, total_compilation_count, failed_compilation_count });
|
try group_end(args.group_name, test_names.len * args.repetitions, total_run);
|
||||||
std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{ args.group_name, total_test_count, ran_test_count, failed_test_count });
|
|
||||||
|
|
||||||
if (failed_compilation_count > 0 or failed_test_count > 0) {
|
|
||||||
return error.fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runBuildTests(allocator: Allocator, args: struct {
|
fn runBuildTests(allocator: Allocator, args: struct {
|
||||||
@ -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
4
retest/c_abi/main.nat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fn[cc(.c)] main[export]() s32
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user