From f0971d4c25820e169c7f53b8efa72db88dcaf237 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Thu, 1 Feb 2024 13:42:48 +0100 Subject: [PATCH] improvements towards compiling on MacOS --- .github/workflows/ci.yml | 14 +++++ bootstrap/Compilation.zig | 2 +- bootstrap/backend/llvm.cpp | 52 ++++++++++++++----- bootstrap/backend/llvm.zig | 80 ++++++++++++++++++++++------- bootstrap/backend/llvm_bindings.zig | 5 +- build.zig | 3 ++ 6 files changed, 121 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dd5445..26ea6da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,3 +22,17 @@ jobs: version: master - name: Test run: zig build test -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native -Dself_hosted_ci=true + # macos_m1: + # runs-on: macos-14 + # timeout-minutes: 15 + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # - name: Set up Zig + # uses: davidgm94/setup-zig@foo + # with: + # version: master + # - name: Test zig + # run: zig version + # - name: Test macos + # run: zig build test -Dthird_party_ci=true -Dtarget=aarch64-macos-none -Dcpu=apple_m1 diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 2e02823..8936bc9 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -319,7 +319,7 @@ pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger } pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn { - const print_stack_trace = false; + const print_stack_trace = @import("configuration").print_stack_trace; switch (print_stack_trace) { true => @call(.always_inline, std.builtin.default_panic, .{ message, stack_trace, return_address }), false => { diff --git a/bootstrap/backend/llvm.cpp b/bootstrap/backend/llvm.cpp index 9ecf1f3..8125080 100644 --- a/bootstrap/backend/llvm.cpp +++ b/bootstrap/backend/llvm.cpp @@ -774,6 +774,10 @@ namespace lld { bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); } + namespace macho { + bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); + } } extern "C" bool NativityLLVMGenerateMachineCode(Module& module, const char* object_file_path_ptr, size_t object_file_path_len, const char* file_path_ptr, size_t file_path_len) @@ -798,11 +802,6 @@ extern "C" bool NativityLLVMGenerateMachineCode(Module& module, const char* obje module.setDataLayout(target_machine->createDataLayout()); module.setTargetTriple(target_triple); -#if 0 - SmallVector bytes; - raw_svector_ostream message_stream(bytes); - auto stream = buffer_ostream(message_stream); -#else std::error_code EC; auto object_file_path = StringRef(object_file_path_ptr, object_file_path_len); raw_fd_ostream stream(object_file_path, EC, sys::fs::OF_None); @@ -810,7 +809,6 @@ extern "C" bool NativityLLVMGenerateMachineCode(Module& module, const char* obje return false; } -#endif legacy::PassManager pass; bool result = target_machine->addPassesToEmitFile(pass, stream, nullptr, llvm::CGFT_ObjectFile, false); if (result) { @@ -821,17 +819,43 @@ extern "C" bool NativityLLVMGenerateMachineCode(Module& module, const char* obje pass.run(module); stream.flush(); - std::vector args; - args.push_back("ld.lld"); - args.push_back(object_file_path_ptr); - args.push_back("-o"); - args.push_back(file_path_ptr); - - lld::elf::link(args, llvm::outs(), llvm::errs(), true, false); - return true; } +enum class Format { + elf = 0, + macho = 1, + coff = 2, +}; + +extern "C" bool NativityLLDLink(Format format, const char** argument_ptr, size_t argument_count, const char** stdout_ptr, size_t* stdout_len, const char** stderr_ptr, size_t* stderr_len) +{ + auto arguments = ArrayRef(argument_ptr, argument_count); + std::string stdout_string; + raw_string_ostream stdout_stream(stdout_string); + + std::string stderr_string; + raw_string_ostream stderr_stream(stderr_string); + + bool success = false; + switch (format) { + case Format::elf: + success = lld::elf::link(arguments, stdout_stream, stderr_stream, true, false); + break; + case Format::coff: + success = lld::coff::link(arguments, stdout_stream, stderr_stream, true, false); + case Format::macho: + success = lld::macho::link(arguments, stdout_stream, stderr_stream, true, false); + default: + break; + } + + stream_to_string(stdout_stream, stdout_ptr, stdout_len); + stream_to_string(stderr_stream, stderr_ptr, stderr_len); + + return success; +} + extern "C" bool NativityLLVMCompareTypes(Type* a, Type* b) { if (auto* int_a = dyn_cast(a)) { diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index 9c050f2..bf4af2f 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -90,6 +90,7 @@ pub const LLVM = struct { const toString = bindings.NativityLLVMModuleToString; const getIntrinsicDeclaration = bindings.NativityLLVMModuleGetIntrinsicDeclaration; const createDebugInfoBuilder = bindings.NativityLLVMModuleCreateDebugInfoBuilder; + const generateMachineCode = bindings.NativityLLVMGenerateMachineCode; }; pub const Builder = opaque { @@ -2925,6 +2926,12 @@ const Error = error{ const address_space = 0; +pub const Format = enum(c_uint) { + elf = 0, + macho = 1, + coff = 2, +}; + pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !void { const llvm_context = LLVM.Context.create() orelse return Error.context; const module = LLVM.Module.create(@ptrCast(unit.descriptor.name.ptr), unit.descriptor.name.len, llvm_context) orelse return Error.module; @@ -3286,13 +3293,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const value = if (llvm.llvm_value_map.get(load.value)) |v| v else blk: { const value = switch (load.value.value) { .runtime => |instr_index| llvm.llvm_instruction_map.get(instr_index).?, - // const instruction = unit.instructions.get(instr_index); - // break :b switch (instruction.*) { - // .argument_declaration => llvm.argument_allocas.get(instr_index).?, - // .stack_slot => unreachable, - // else => |t| @panic(@tagName(t)), - // }; - // }, else => |t| @panic(@tagName(t)), }; try llvm.llvm_value_map.putNoClobber(context.allocator, load.value, value); @@ -3401,13 +3401,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo .@"unreachable" => { _ = llvm.builder.createUnreachable() orelse return LLVM.Value.Instruction.Error.@"unreachable"; }, - // .fetch_global => |global_declaration| { - // const global_variable = llvm.global_variable_map.get(global_declaration).?; - // const global_type = try llvm.getType(unit, context, global_declaration.declaration.type); - // const is_volatile = false; - // const load = llvm.builder.createLoad(global_type, global_variable.toValue(), is_volatile, "global", "global".len) orelse return LLVM.Value.Instruction.Error.load; - // try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, load.toValue()); - // }, else => |t| @panic(@tagName(t)), } } @@ -3443,10 +3436,10 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo di_builder.finalize(); } - var module_len: usize = 0; - const module_ptr = llvm.module.toString(&module_len); - const module_string = module_ptr[0..module_len]; - logln(.llvm, .print_module, "{s}", .{module_string}); + var module_len: usize = 0; + const module_ptr = llvm.module.toString(&module_len); + const module_string = module_ptr[0..module_len]; + logln(.llvm, .print_module, "{s}", .{module_string}); const verify_module = true; if (verify_module) { @@ -3461,8 +3454,57 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const file_path = unit.descriptor.executable_path; const object_file_path = try std.mem.joinZ(context.allocator, "", &.{ file_path, ".o" }); const destination_file_path = try std.mem.joinZ(context.allocator, "", &.{file_path}); - const r = bindings.NativityLLVMGenerateMachineCode(llvm.module, object_file_path.ptr, object_file_path.len, destination_file_path.ptr, destination_file_path.len); + const r = llvm.module.generateMachineCode(object_file_path.ptr, object_file_path.len, destination_file_path.ptr, destination_file_path.len); if (!r) { @panic("Compilation failed!"); } + + const format: Format = switch (unit.descriptor.target.os.tag) { + .windows => .coff, + .macos => .macho, + .linux => .elf, + else => unreachable, + }; + + const driver_program = switch (format) { + .coff => "lld-link", + .elf => "ld.lld", + .macho => "ld64.lld", + }; + var arguments = ArrayList([*:0]const u8){}; + try arguments.append(context.allocator, driver_program); + + try arguments.append(context.allocator, object_file_path.ptr); + try arguments.append(context.allocator, "-o"); + try arguments.append(context.allocator, destination_file_path.ptr); + + if (format == .macho) { + try arguments.append(context.allocator, "-platform_version"); + try arguments.append(context.allocator, "macos"); + try arguments.append(context.allocator, "11"); + try arguments.append(context.allocator, "14"); + try arguments.append(context.allocator, "-arch"); + try arguments.append(context.allocator, "arm64"); + try arguments.append(context.allocator, "-lSystem"); + + } + + var stdout_ptr: [*]const u8 = undefined; + var stdout_len: usize = 0; + var stderr_ptr: [*]const u8 = undefined; + var stderr_len: usize = 0; + + const linking_result = bindings.NativityLLDLink(format, arguments.items.ptr, arguments.items.len, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len); + + if (stdout_len > 0) { + std.debug.print("{s}\n", .{stdout_ptr[0..stdout_len]}); + } + + if (stderr_len > 0) { + std.debug.print("{s}\n", .{stderr_ptr[0..stderr_len]}); + } + + if (!linking_result) { + std.debug.panic("Linker invokation failed: {s}", .{arguments.items}); + } } diff --git a/bootstrap/backend/llvm_bindings.zig b/bootstrap/backend/llvm_bindings.zig index 0f58b54..dd86003 100644 --- a/bootstrap/backend/llvm_bindings.zig +++ b/bootstrap/backend/llvm_bindings.zig @@ -83,7 +83,7 @@ pub extern fn NativityLLVMVerifyModule(module: *LLVM.Module, message_ptr: *[*]co pub extern fn NativityLLVMModuleToString(module: *LLVM.Module, message_len: *usize) [*]const u8; pub extern fn NativityLLVMFunctionToString(function: *LLVM.Value.Function, message_len: *usize) [*]const u8; -pub extern fn NativityLLVMGenerateMachineCode(module: *LLVM.Module, object_file_path_ptr: [*]const u8, object_file_path_len: usize, file_path_ptr: [*]const u8, file_path_len: usize) bool; + pub extern fn NativityLLVMBuilderIsCurrentBlockTerminated(builder: *LLVM.Builder) bool; pub extern fn NativityLLVMGetUndefined(type: *LLVM.Type) ?*LLVM.Value.Constant.Undefined; pub extern fn NativityLLVMFunctionSetCallingConvention(function: *LLVM.Value.Function, calling_convention: LLVM.Value.Function.CallingConvention) void; @@ -117,3 +117,6 @@ pub extern fn NativityLLVMCreatePhiNode(type: *LLVM.Type, reserved_value_count: pub extern fn NativityLLVMAllocatGetAllocatedType(alloca: *LLVM.Value.Instruction.Alloca) *LLVM.Type; pub extern fn NativityLLVMValueToAlloca(value: *LLVM.Value) ?*LLVM.Value.Instruction.Alloca; pub extern fn NativityLLVMGlobalVariableSetInitializer(global_variable: *LLVM.Value.Constant.GlobalVariable, constant_initializer: *LLVM.Value.Constant) void; + +pub extern fn NativityLLVMGenerateMachineCode(module: *LLVM.Module, object_file_path_ptr: [*]const u8, object_file_path_len: usize, file_path_ptr: [*]const u8, file_path_len: usize) bool; +pub extern fn NativityLLDLink(format: llvm.Format, argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool; diff --git a/build.zig b/build.zig index e121a1d..f3267b5 100644 --- a/build.zig +++ b/build.zig @@ -68,6 +68,8 @@ pub fn build(b: *std.Build) !void { }; } }; + const compiler_options = b.addOptions(); + compiler_options.addOption(bool, "print_stack_trace", is_ci); const compiler = b.addExecutable(.{ .name = "nat", @@ -75,6 +77,7 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimization, }); + compiler.root_module.addOptions("configuration", compiler_options); compiler.formatted_panics = is_ci; compiler.root_module.unwind_tables = is_ci; compiler.root_module.omit_frame_pointer = false;