Merge pull request #139 from birth-software/integrate-optimization-pipeline
Integrate optimization pipeline
This commit is contained in:
commit
b6dd3d0807
@ -49,6 +49,17 @@ const SliceField = enum {
|
||||
|
||||
const length_field_name = @tagName(SliceField.length);
|
||||
|
||||
const Optimization = enum{
|
||||
none,
|
||||
debug_prefer_fast,
|
||||
debug_prefer_size,
|
||||
lightly_optimize_for_speed,
|
||||
optimize_for_speed,
|
||||
optimize_for_size,
|
||||
aggressively_optimize_for_speed,
|
||||
aggressively_optimize_for_size,
|
||||
};
|
||||
|
||||
pub fn createContext(allocator: Allocator, my_allocator: *MyAllocator) !*const Context {
|
||||
const context: *Context = try allocator.create(Context);
|
||||
|
||||
@ -96,6 +107,7 @@ pub fn compileBuildExecutable(context: *const Context, arguments: []const []cons
|
||||
.object_path = "nat/build.o",
|
||||
.link_libc = @import("builtin").os.tag == .macos,
|
||||
.link_libcpp = false,
|
||||
.optimization = .none,
|
||||
.generate_debug_information = true,
|
||||
.name = "build",
|
||||
.is_test = false,
|
||||
@ -2790,6 +2802,7 @@ pub fn buildExecutable(context: *const Context, arguments: []const []const u8, o
|
||||
var link_libc = false;
|
||||
var maybe_executable_name: ?[]const u8 = null;
|
||||
var c_source_files = UnpinnedArray([]const u8){};
|
||||
var optimization = Optimization.none;
|
||||
const generate_debug_information = true;
|
||||
|
||||
if (arguments.len == 0) return error.InvalidInput;
|
||||
@ -2907,6 +2920,15 @@ pub fn buildExecutable(context: *const Context, arguments: []const []const u8, o
|
||||
} else {
|
||||
reportUnterminatedArgumentError(current_argument);
|
||||
}
|
||||
} else if (byte_equal(current_argument, "-optimize")) {
|
||||
if (i + 1 != arguments.len) {
|
||||
i += 1;
|
||||
|
||||
const optimize_string = arguments[i];
|
||||
optimization = data_structures.enumFromString(Optimization, optimize_string) orelse unreachable;
|
||||
} else {
|
||||
reportUnterminatedArgumentError(current_argument);
|
||||
}
|
||||
} else {
|
||||
@panic(current_argument);
|
||||
// std.debug.panic("Unrecognized argument: {s}", .{current_argument});
|
||||
@ -2948,6 +2970,7 @@ pub fn buildExecutable(context: *const Context, arguments: []const []const u8, o
|
||||
.arch = arch,
|
||||
.os = os,
|
||||
.abi = abi,
|
||||
.optimization = optimization,
|
||||
.link_libc = switch (os) {
|
||||
.linux => link_libc,
|
||||
.macos => true,
|
||||
@ -16364,6 +16387,7 @@ pub const Descriptor = struct {
|
||||
arch: Arch,
|
||||
os: Os,
|
||||
abi: Abi,
|
||||
optimization: Optimization,
|
||||
only_parse: bool,
|
||||
link_libc: bool,
|
||||
link_libcpp: bool,
|
||||
@ -16691,3 +16715,5 @@ pub fn write(kind: LogKind, string: []const u8) !void {
|
||||
try std.io.getStdOut().writeAll(string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,6 +123,7 @@ pub const LLVM = struct {
|
||||
const createDebugInfoBuilder = bindings.NativityLLVMModuleCreateDebugInfoBuilder;
|
||||
const setTargetMachineDataLayout = bindings.NativityLLVMModuleSetTargetMachineDataLayout;
|
||||
const setTargetTriple = bindings.NativityLLVMModuleSetTargetTriple;
|
||||
const runOptimizationPipeline = bindings.NativityLLVMRunOptimizationPipeline;
|
||||
const addPassesToEmitFile = bindings.NativityLLVMModuleAddPassesToEmitFile;
|
||||
};
|
||||
|
||||
@ -498,6 +499,11 @@ pub const LLVM = struct {
|
||||
aggressive = 3,
|
||||
};
|
||||
|
||||
pub const OptimizationLevel = extern struct{
|
||||
speed_level: c_uint,
|
||||
size_level: c_uint,
|
||||
};
|
||||
|
||||
pub const FramePointerKind = enum(c_uint) {
|
||||
none = 0,
|
||||
non_leaf = 1,
|
||||
@ -2341,18 +2347,23 @@ pub const LLVM = struct {
|
||||
function.setSubprogram(subprogram);
|
||||
|
||||
switch (declaration.initial_value) {
|
||||
.function_declaration => {
|
||||
try llvm.llvm_external_functions.put_no_clobber(context.my_allocator, declaration, function);
|
||||
},
|
||||
.function_definition => |function_definition_index| {
|
||||
const function_definition = unit.function_definitions.get(function_definition_index);
|
||||
const scope = subprogram.toLocalScope().toScope();
|
||||
|
||||
try llvm.scope_map.put_no_clobber(context.my_allocator, &function_definition.scope.scope, scope);
|
||||
},
|
||||
.function_declaration => {},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
|
||||
switch (declaration.initial_value) {
|
||||
.function_declaration => try llvm.llvm_external_functions.put_no_clobber(context.my_allocator, declaration, function),
|
||||
.function_definition => {},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -2392,7 +2403,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.context = llvm_context,
|
||||
.module = module,
|
||||
.builder = builder,
|
||||
.debug_info_builder = module.createDebugInfoBuilder() orelse return Error.debug_info_builder,
|
||||
.debug_info_builder = if (unit.descriptor.generate_debug_information) module.createDebugInfoBuilder() orelse return Error.debug_info_builder else undefined,
|
||||
.attributes = .{
|
||||
.naked = llvm_context.getAttributeFromEnum(.Naked, 0),
|
||||
.noreturn = llvm_context.getAttributeFromEnum(.NoReturn, 0),
|
||||
@ -2401,6 +2412,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.@"noalias" = llvm_context.getAttributeFromEnum(.NoAlias, 0),
|
||||
},
|
||||
};
|
||||
unit.descriptor.generate_debug_information = false;
|
||||
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const full_path = try std.fs.cwd().realpathAlloc(context.allocator, unit.descriptor.main_package_path);
|
||||
@ -2531,30 +2543,35 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
|
||||
switch (sema_instruction.*) {
|
||||
.push_scope => |push_scope| {
|
||||
const old_scope = try llvm.getScope(unit, context, push_scope.old);
|
||||
assert(@intFromEnum(push_scope.old.kind) >= @intFromEnum(Compilation.Debug.Scope.Kind.function));
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const old_scope = try llvm.getScope(unit, context, push_scope.old);
|
||||
assert(@intFromEnum(push_scope.old.kind) >= @intFromEnum(Compilation.Debug.Scope.Kind.function));
|
||||
|
||||
const lexical_block = llvm.debug_info_builder.createLexicalBlock(old_scope, llvm.file, push_scope.new.line + 1, push_scope.new.column + 1) orelse unreachable;
|
||||
try llvm.scope_map.put_no_clobber(context.my_allocator, push_scope.new, lexical_block.toScope());
|
||||
llvm.scope = lexical_block.toScope();
|
||||
const lexical_block = llvm.debug_info_builder.createLexicalBlock(old_scope, llvm.file, push_scope.new.line + 1, push_scope.new.column + 1) orelse unreachable;
|
||||
try llvm.scope_map.put_no_clobber(context.my_allocator, push_scope.new, lexical_block.toScope());
|
||||
llvm.scope = lexical_block.toScope();
|
||||
}
|
||||
},
|
||||
.pop_scope => |pop_scope| {
|
||||
const new = try llvm.getScope(unit, context, pop_scope.new);
|
||||
if (pop_scope.new.kind == .function) {
|
||||
assert(new.toSubprogram() orelse unreachable == llvm.function.getSubprogram() orelse unreachable);
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const new = try llvm.getScope(unit, context, pop_scope.new);
|
||||
if (pop_scope.new.kind == .function) {
|
||||
assert(new.toSubprogram() orelse unreachable == llvm.function.getSubprogram() orelse unreachable);
|
||||
}
|
||||
llvm.scope = new;
|
||||
var scope = pop_scope.old;
|
||||
while (scope.kind != .function) {
|
||||
scope = scope.parent.?;
|
||||
}
|
||||
const subprogram_scope = try llvm.getScope(unit, context, scope);
|
||||
assert(llvm.function.getSubprogram() orelse unreachable == subprogram_scope.toSubprogram() orelse unreachable);
|
||||
}
|
||||
llvm.scope = new;
|
||||
var scope = pop_scope.old;
|
||||
while (scope.kind != .function) {
|
||||
scope = scope.parent.?;
|
||||
}
|
||||
const subprogram_scope = try llvm.getScope(unit, context, scope);
|
||||
assert(llvm.function.getSubprogram() orelse unreachable == subprogram_scope.toSubprogram() orelse unreachable);
|
||||
},
|
||||
.debug_checkpoint => |debug_checkpoint| {
|
||||
const scope = try llvm.getScope(unit, context, debug_checkpoint.scope);
|
||||
// assert(scope == llvm.scope);
|
||||
llvm.builder.setCurrentDebugLocation(llvm.context, debug_checkpoint.line + 1, debug_checkpoint.column + 1, scope, llvm.function);
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const scope = try llvm.getScope(unit, context, debug_checkpoint.scope);
|
||||
llvm.builder.setCurrentDebugLocation(llvm.context, debug_checkpoint.line + 1, debug_checkpoint.column + 1, scope, llvm.function);
|
||||
}
|
||||
},
|
||||
.inline_assembly => |inline_assembly_index| {
|
||||
const assembly_block = unit.inline_assembly.get(inline_assembly_index);
|
||||
@ -3251,7 +3268,13 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const jit = false;
|
||||
const code_model: LLVM.CodeModel = undefined;
|
||||
const is_code_model_present = false;
|
||||
const codegen_optimization_level = LLVM.CodegenOptimizationLevel.none;
|
||||
const codegen_optimization_level: LLVM.CodegenOptimizationLevel = switch (unit.descriptor.optimization) {
|
||||
.none => .none,
|
||||
.debug_prefer_fast, .debug_prefer_size => .none,
|
||||
.lightly_optimize_for_speed => .less,
|
||||
.optimize_for_speed, .optimize_for_size => .default,
|
||||
.aggressively_optimize_for_speed, .aggressively_optimize_for_size => .aggressive,
|
||||
};
|
||||
const target_machine = target.createTargetMachine(target_triple.ptr, target_triple.len, cpu, cpu.len, features, features.len, LLVM.RelocationModel.static, code_model, is_code_model_present, codegen_optimization_level, jit) orelse unreachable;
|
||||
llvm.module.setTargetMachineDataLayout(target_machine);
|
||||
llvm.module.setTargetTriple(target_triple.ptr, target_triple.len);
|
||||
@ -3265,6 +3288,21 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const object_file_path = slice[0 .. slice.len - 1 :0];
|
||||
break :blk object_file_path;
|
||||
};
|
||||
|
||||
if (unit.descriptor.optimization != .none) {
|
||||
const optimization_level: LLVM.OptimizationLevel = switch (unit.descriptor.optimization) {
|
||||
.none => unreachable,
|
||||
.debug_prefer_fast, .debug_prefer_size => .{ .speed_level = 0, .size_level = 0 }, // -O0
|
||||
.lightly_optimize_for_speed => .{ .speed_level = 1, .size_level = 0 }, // -O1
|
||||
.optimize_for_speed => .{ .speed_level = 2, .size_level = 0 }, // -O2
|
||||
.optimize_for_size => .{ .speed_level = 2, .size_level = 1 }, // -Os
|
||||
.aggressively_optimize_for_speed => .{ .speed_level = 3, .size_level = 0 }, // -O3
|
||||
.aggressively_optimize_for_size => .{ .speed_level = 2, .size_level = 2 }, // -Oz
|
||||
};
|
||||
|
||||
llvm.module.runOptimizationPipeline(target_machine, optimization_level);
|
||||
}
|
||||
|
||||
const disable_verify = false;
|
||||
const result = llvm.module.addPassesToEmitFile(target_machine, object_file_path.ptr, object_file_path.len, LLVM.CodeGenFileType.object, disable_verify);
|
||||
if (!result) {
|
||||
|
@ -150,6 +150,7 @@ pub extern fn NativityLLVMGetTarget(target_triple_ptr: [*]const u8, target_tripl
|
||||
pub extern fn NativityLLVMTargetCreateTargetMachine(target: *LLVM.Target, target_triple_ptr: [*]const u8, target_triple_len: usize, cpu_ptr: [*]const u8, cpu_len: usize, features_ptr: [*]const u8, features_len: usize, relocation_model: LLVM.RelocationModel, maybe_code_model: LLVM.CodeModel, is_code_model_present: bool, optimization_level: LLVM.CodegenOptimizationLevel, jit: bool) ?*LLVM.Target.Machine;
|
||||
pub extern fn NativityLLVMModuleSetTargetMachineDataLayout(module: *LLVM.Module, target_machine: *LLVM.Target.Machine) void;
|
||||
pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void;
|
||||
pub extern fn NativityLLVMRunOptimizationPipeline(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, optimization_level: LLVM.OptimizationLevel) void;
|
||||
pub extern fn NativityLLVMModuleAddPassesToEmitFile(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, object_file_path_ptr: [*]const u8, object_file_path_len: usize, codegen_file_type: LLVM.CodeGenFileType, disable_verify: bool) bool;
|
||||
pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void;
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false;
|
||||
const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false;
|
||||
const is_ci = self_hosted_ci or third_party_ci;
|
||||
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci; //or os == .macos;
|
||||
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or os == .macos;
|
||||
const native_target = b.resolveTargetQuery(.{});
|
||||
const optimization = b.standardOptimizeOption(.{});
|
||||
const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false;
|
||||
|
@ -36,6 +36,7 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
group_name: []const u8,
|
||||
self_hosted: bool,
|
||||
is_test: bool,
|
||||
compiler_path: []const u8,
|
||||
}) !void {
|
||||
const test_names = try collectDirectoryDirEntries(allocator, args.directory_path);
|
||||
|
||||
@ -55,7 +56,7 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path },
|
||||
.argv = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path },
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
ran_compilation_count += 1;
|
||||
@ -120,100 +121,16 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn runStandaloneTests(allocator: Allocator, args: struct {
|
||||
self_hosted: bool,
|
||||
}) !void {
|
||||
const standalone_test_dir_path = "test/standalone";
|
||||
const standalone_test_names = try collectDirectoryDirEntries(allocator, standalone_test_dir_path);
|
||||
|
||||
const total_compilation_count = standalone_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 = standalone_test_names.len;
|
||||
|
||||
for (standalone_test_names) |standalone_test_name| {
|
||||
std.debug.print("{s}... ", .{standalone_test_name});
|
||||
const source_file_path = try std.mem.concat(allocator, u8, &.{ standalone_test_dir_path, "/", standalone_test_name, "/main.nat" });
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, "exe", "-main_source_file", source_file_path },
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
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/", standalone_test_name });
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.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("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{ total_compilation_count, failed_compilation_count });
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ 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 {
|
||||
self_hosted: bool,
|
||||
compiler_path: []const u8,
|
||||
}) !void {
|
||||
std.debug.print("\n[BUILD TESTS]\n\n", .{});
|
||||
const previous_cwd = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
const test_dir_path = "test/build";
|
||||
const test_names = try collectDirectoryDirEntries(allocator, test_dir_path);
|
||||
const test_dir_realpath = try std.fs.cwd().realpathAlloc(allocator, test_dir_path);
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path);
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, args.compiler_path);
|
||||
try std.posix.chdir(test_dir_realpath);
|
||||
|
||||
const total_compilation_count = test_names.len;
|
||||
@ -303,13 +220,14 @@ fn runBuildTests(allocator: Allocator, args: struct {
|
||||
|
||||
fn runStdTests(allocator: Allocator, args: struct {
|
||||
self_hosted: bool,
|
||||
compiler_path: []const u8,
|
||||
}) !void {
|
||||
var errors = false;
|
||||
std.debug.print("std... ", .{});
|
||||
|
||||
const result = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, "test", "-main_source_file", "lib/std/std.nat", "-name", "std" },
|
||||
.argv = &.{ args.compiler_path, "test", "-main_source_file", "lib/std/std.nat", "-name", "std" },
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
const compilation_result: TestError!bool = switch (result.term) {
|
||||
@ -362,12 +280,16 @@ fn runStdTests(allocator: Allocator, args: struct {
|
||||
if (errors) return error.fail;
|
||||
}
|
||||
|
||||
fn runCmakeTests(allocator: Allocator, dir_path: []const u8) !void {
|
||||
fn runCmakeTests(allocator: Allocator, args: struct {
|
||||
dir_path: []const u8,
|
||||
compiler_path: []const u8,
|
||||
}) !void {
|
||||
var errors = false;
|
||||
const original_dir = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
const cc_dir = try std.fs.cwd().openDir(dir_path, .{
|
||||
const cc_dir = try std.fs.cwd().openDir(args.dir_path, .{
|
||||
.iterate = true,
|
||||
});
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, args.compiler_path);
|
||||
|
||||
const cc_dir_path = try cc_dir.realpathAlloc(allocator, ".");
|
||||
try std.posix.chdir(cc_dir_path);
|
||||
@ -392,9 +314,9 @@ fn runCmakeTests(allocator: Allocator, dir_path: []const u8) !void {
|
||||
// "--debug-output",
|
||||
// "-G", "Unix Makefiles",
|
||||
// "-DCMAKE_VERBOSE_MAKEFILE=On",
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_C_COMPILER=", "nat;cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", "nat;c++" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", "nat;cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_C_COMPILER=", compiler_realpath, ";cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", compiler_realpath, ";c++" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", compiler_realpath, ";cc" }),
|
||||
},
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
@ -500,11 +422,13 @@ const self_hosted_relative_path = "nat/" ++ self_hosted_exe_name;
|
||||
|
||||
fn compile_self_hosted(allocator: Allocator, args: struct {
|
||||
is_test: bool,
|
||||
}) !void {
|
||||
optimization: Optimization,
|
||||
}) ![]const u8 {
|
||||
const name = try std.mem.concat(allocator, u8, &.{self_hosted_exe_name, "_", @tagName(args.optimization)});
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ bootstrap_relative_path, if (args.is_test) "test" else "exe", "-main_source_file", "src/main.nat", "-name", self_hosted_exe_name },
|
||||
.argv = &.{ bootstrap_relative_path, if (args.is_test) "test" else "exe", "-main_source_file", "src/main.nat", "-name", name, "-optimize", @tagName(args.optimization) },
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
|
||||
@ -515,8 +439,6 @@ fn compile_self_hosted(allocator: Allocator, args: struct {
|
||||
.Unknown => error.unknown,
|
||||
};
|
||||
|
||||
|
||||
|
||||
_ = compilation_result catch |err| {
|
||||
std.debug.print("Compiling the self-hosted compiler failed!\n", .{});
|
||||
if (compile_run.stdout.len > 0) {
|
||||
@ -527,47 +449,75 @@ fn compile_self_hosted(allocator: Allocator, args: struct {
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
return try std.mem.concat(allocator, u8, &.{"nat/", name});
|
||||
}
|
||||
|
||||
const Optimization = enum{
|
||||
none,
|
||||
debug_prefer_fast,
|
||||
debug_prefer_size,
|
||||
lightly_optimize_for_speed,
|
||||
optimize_for_speed,
|
||||
optimize_for_size,
|
||||
aggressively_optimize_for_speed,
|
||||
aggressively_optimize_for_size,
|
||||
};
|
||||
|
||||
fn run_test_suite(allocator: Allocator, args: struct {
|
||||
self_hosted: bool,
|
||||
compiler_path: []const u8,
|
||||
}) bool {
|
||||
const self_hosted = args.self_hosted;
|
||||
std.debug.print("TESTING {s} COMPILER...\n=================\n", .{if (self_hosted) "SELF-HOSTED" else "BOOTSTRAP"});
|
||||
std.debug.print("TESTING {s} COMPILER: {s}...\n=================\n", .{if (self_hosted) "SELF-HOSTED" else "BOOTSTRAP", args.compiler_path});
|
||||
var errors = false;
|
||||
|
||||
runStandalone(allocator, .{
|
||||
.directory_path = "test/standalone",
|
||||
.group_name = "STANDALONE",
|
||||
.is_test = false,
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
runBuildTests(allocator, .{
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
runStandalone(allocator, .{
|
||||
.directory_path = "test/tests",
|
||||
.group_name = "TEST EXECUTABLE",
|
||||
.is_test = true,
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
//
|
||||
|
||||
runStdTests(allocator, .{
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
if (!self_hosted) {
|
||||
runCmakeTests(allocator, "test/cc") catch {
|
||||
runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc",
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
runCmakeTests(allocator, "test/c++") catch {
|
||||
|
||||
runCmakeTests(allocator, .{
|
||||
.dir_path = "test/c++",
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
@ -575,7 +525,10 @@ fn run_test_suite(allocator: Allocator, args: struct {
|
||||
.macos => {},
|
||||
.windows => {},
|
||||
.linux => switch (@import("builtin").abi) {
|
||||
.gnu => runCmakeTests(allocator, "test/cc_linux") catch {
|
||||
.gnu => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_linux",
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
},
|
||||
.musl => {},
|
||||
@ -594,18 +547,24 @@ pub fn main() !void {
|
||||
|
||||
var errors = run_test_suite(allocator, .{
|
||||
.self_hosted = false,
|
||||
.compiler_path = bootstrap_relative_path,
|
||||
});
|
||||
|
||||
if (!errors) {
|
||||
if (compile_self_hosted(allocator, .{
|
||||
.is_test = false,
|
||||
})) |_| {
|
||||
errors = errors or run_test_suite(allocator, .{
|
||||
.self_hosted = true,
|
||||
});
|
||||
} else |err| {
|
||||
err catch {};
|
||||
errors = true;
|
||||
inline for (@typeInfo(Optimization).Enum.fields) |opt| {
|
||||
const optimization = @field(Optimization, opt.name);
|
||||
if (compile_self_hosted(allocator, .{
|
||||
.is_test = false,
|
||||
.optimization = optimization,
|
||||
})) |compiler_path| {
|
||||
errors = errors or run_test_suite(allocator, .{
|
||||
.self_hosted = true,
|
||||
.compiler_path = compiler_path,
|
||||
});
|
||||
} else |err| {
|
||||
err catch {};
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,7 @@ const assert = std.assert;
|
||||
const Allocator = std.Allocator;
|
||||
const Target = std.Target;
|
||||
|
||||
const Optimization = enum{
|
||||
none,
|
||||
light,
|
||||
prefer_size,
|
||||
prefer_speed,
|
||||
speed_aggressive,
|
||||
size_aggressive,
|
||||
};
|
||||
const Optimization = std.builtin.Optimization;
|
||||
|
||||
const Executable = struct{
|
||||
target: Target,
|
||||
|
@ -12,7 +12,8 @@ const Cpu = enum{
|
||||
|
||||
const Abi = enum{
|
||||
none,
|
||||
gnu, msvc,
|
||||
gnu,
|
||||
msvc,
|
||||
};
|
||||
|
||||
const CallingConvention = enum{
|
||||
@ -37,3 +38,14 @@ const TestFunction = struct{
|
||||
const StructOptions = struct{
|
||||
sliceable: bool = false,
|
||||
};
|
||||
|
||||
const Optimization = enum{
|
||||
none,
|
||||
debug_prefer_fast,
|
||||
debug_prefer_size,
|
||||
lightly_optimize_for_speed,
|
||||
optimize_for_speed,
|
||||
optimize_for_size,
|
||||
aggressively_optimize_for_speed,
|
||||
aggressively_optimize_for_size,
|
||||
};
|
||||
|
@ -935,17 +935,18 @@ extern "C" void NativityLLVMModuleSetTargetTriple(Module& module, const char* ta
|
||||
module.setTargetTriple(target_triple);
|
||||
}
|
||||
|
||||
extern "C" void NativityLLVMRunOptimizationPipeline(Module& module, TargetMachine& target_machine)
|
||||
extern "C" void NativityLLVMRunOptimizationPipeline(Module& module, TargetMachine& target_machine, OptimizationLevel optimization_level)
|
||||
{
|
||||
// TODO: PGO
|
||||
// TODO: CS profile
|
||||
bool loop_optimizations = !optimization_level.isOptimizingForSize() && optimization_level.getSpeedupLevel() >= 2;
|
||||
|
||||
llvm::PipelineTuningOptions pipeline_tuning_options;
|
||||
pipeline_tuning_options.LoopUnrolling = false;
|
||||
pipeline_tuning_options.LoopInterleaving = false;
|
||||
pipeline_tuning_options.LoopVectorization = false;
|
||||
pipeline_tuning_options.SLPVectorization = false;
|
||||
pipeline_tuning_options.MergeFunctions = false;
|
||||
pipeline_tuning_options.LoopUnrolling = loop_optimizations;
|
||||
pipeline_tuning_options.LoopInterleaving = loop_optimizations;
|
||||
pipeline_tuning_options.LoopVectorization = loop_optimizations;
|
||||
pipeline_tuning_options.SLPVectorization = loop_optimizations;
|
||||
pipeline_tuning_options.MergeFunctions = true;
|
||||
pipeline_tuning_options.CallGraphProfile = false;
|
||||
pipeline_tuning_options.UnifiedLTO = false;
|
||||
|
||||
@ -971,7 +972,6 @@ extern "C" void NativityLLVMRunOptimizationPipeline(Module& module, TargetMachin
|
||||
|
||||
ModulePassManager module_pass_manager;
|
||||
|
||||
OptimizationLevel optimization_level = OptimizationLevel::O0;
|
||||
bool thin_lto = false;
|
||||
bool lto = false;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user