diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index da68afc..4764f79 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -53,6 +53,22 @@ pub const LLVM = struct { tag_count: c_uint = 0, inside_branch: bool = false, + pub const x86_64 = struct{ + pub const initializeTarget = bindings.LLVMInitializeX86Target; + pub const initializeTargetInfo = bindings.LLVMInitializeX86TargetInfo; + pub const initializeTargetMC = bindings.LLVMInitializeX86TargetMC; + pub const initializeAsmPrinter = bindings.LLVMInitializeX86AsmPrinter; + pub const initializeAsmParser = bindings.LLVMInitializeX86AsmParser; + }; + + pub const aarch64 = struct{ + pub const initializeTarget = bindings.LLVMInitializeAArch64Target; + pub const initializeTargetInfo = bindings.LLVMInitializeAArch64TargetInfo; + pub const initializeTargetMC = bindings.LLVMInitializeAArch64TargetMC; + pub const initializeAsmPrinter = bindings.LLVMInitializeAArch64AsmPrinter; + pub const initializeAsmParser = bindings.LLVMInitializeAArch64AsmParser; + }; + pub const Attributes = struct { noreturn: *Attribute, naked: *Attribute, @@ -475,7 +491,7 @@ pub const LLVM = struct { local_exec = 3, }; - pub const OptimizationLevel = enum(c_int) { + pub const CodegenOptimizationLevel = enum(c_int) { none = 0, less = 1, default = 2, @@ -3142,8 +3158,17 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo try write(.llvm, "\n"); } - // TODO: initialize only the target we are going to use - bindings.NativityLLVMInitializeCodeGeneration(); + switch (unit.descriptor.arch) { + inline else => |a| { + const arch = @field(LLVM, @tagName(a)); + arch.initializeTarget(); + arch.initializeTargetInfo(); + arch.initializeTargetMC(); + arch.initializeAsmPrinter(); + arch.initializeAsmParser(); + } + } + // TODO: proper target selection const target_triple = switch (unit.descriptor.os) { .linux => "x86_64-linux-none", @@ -3161,7 +3186,8 @@ 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 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, LLVM.OptimizationLevel.none, jit) orelse unreachable; + const codegen_optimization_level = LLVM.CodegenOptimizationLevel.none; + 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); const file_path = unit.descriptor.executable_path; @@ -3174,121 +3200,9 @@ 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; }; - // const destination_file_path = blk: { - // const slice = try context.allocator.alloc(u8, file_path.len + 1); // try std.mem.concatWithSentinel(context.allocator, &.{file_path}); - // @memcpy(slice[0..file_path.len], file_path); - // slice[slice.len - 1] = 0; - // const destination_file_path = slice[0..file_path.len :0]; - // break :blk destination_file_path; - // }; - // _ = destination_file_path; // autofix 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) { @panic("can't generate machine code"); } - - // const format: Format = switch (unit.descriptor.os) { - // // .windows => .coff, - // .macos => .macho, - // .linux => .elf, - // // else => unreachable, - // }; - - // const driver_program = switch (format) { - // .coff => "lld-link", - // .elf => "ld.lld", - // .macho => "ld64.lld", - // }; - // _ = driver_program; // autofix - - // var arguments = UnpinnedArray([]const u8){}; - // try arguments.append(context.my_allocator, driver_program); - // - // try arguments.append(context.my_allocator, "--error-limit=0"); - // - // try arguments.append(context.my_allocator, "-o"); - // try arguments.append(context.my_allocator, destination_file_path.ptr); - // - // try arguments.append(context.my_allocator, object_file_path.ptr); - // - // try arguments.append_slice(context.my_allocator, unit.object_files.slice()); - // // for (unit.object_files.slice()) |object_file| { - // // _ = object_file; // autofix - // // } - // - // switch (unit.descriptor.os) { - // .macos => { - // try arguments.append(context.my_allocator, "-dynamic"); - // try arguments.append_slice(context.my_allocator, &.{ "-platform_version", "macos", "13.4.1", "13.3" }); - // try arguments.append(context.my_allocator, "-arch"); - // try arguments.append(context.my_allocator, switch (unit.descriptor.arch) { - // .aarch64 => "arm64", - // else => |t| @panic(@tagName(t)), - // }); - // try arguments.append_slice(context.my_allocator, &.{ "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" }); - // try arguments.append_slice(context.my_allocator, &.{ "-e", "_main" }); - // try arguments.append(context.my_allocator, "-lSystem"); - // }, - // .linux => { - // try arguments.append_slice(context.my_allocator, &.{ "--entry", "_start" }); - // try arguments.append(context.my_allocator, "-m"); - // try arguments.append(context.my_allocator, switch (unit.descriptor.arch) { - // .x86_64 => "elf_x86_64", - // else => |t| @panic(@tagName(t)), - // }); - // - // if (unit.descriptor.link_libc) { - // try arguments.append(context.my_allocator, "/usr/lib/crt1.o"); - // try arguments.append(context.my_allocator, "/usr/lib/crti.o"); - // try arguments.append_slice(context.my_allocator, &.{ "-L", "/usr/lib" }); - // try arguments.append_slice(context.my_allocator, &.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" }); - // try arguments.append(context.my_allocator, "--as-needed"); - // try arguments.append(context.my_allocator, "-lm"); - // try arguments.append(context.my_allocator, "-lpthread"); - // try arguments.append(context.my_allocator, "-lc"); - // try arguments.append(context.my_allocator, "-ldl"); - // try arguments.append(context.my_allocator, "-lrt"); - // try arguments.append(context.my_allocator, "-lutil"); - // try arguments.append(context.my_allocator, "/usr/lib/crtn.o"); - // } - // - // // if (unit.descriptor.link_libc) { - // // try arguments.append_slice(context.allocator, &.{ "-lc" }); - // // } - // }, - // // .windows => {}, - // // else => |t| @panic(@tagName(t)), - // } - // - // 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 = switch (format) { - // .elf => bindings.NativityLLDLinkELF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len), - // .coff => bindings.NativityLLDLinkCOFF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len), - // .macho => bindings.NativityLLDLinkMachO(arguments.pointer, arguments.length, &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) { - // try write(.panic, "\n"); - // for (arguments.slice()) |argument| { - // const arg = data_structures.span(argument); - // try write(.panic, arg); - // try write(.panic, " "); - // } - // try write(.panic, "\n"); - // - // @panic(stderr_ptr[0..stderr_len]); - // } } diff --git a/bootstrap/backend/llvm_bindings.zig b/bootstrap/backend/llvm_bindings.zig index 48b834c..fff5d07 100644 --- a/bootstrap/backend/llvm_bindings.zig +++ b/bootstrap/backend/llvm_bindings.zig @@ -147,8 +147,119 @@ pub extern fn NativityLLVMGlobalVariableSetInitializer(global_variable: *LLVM.Va pub extern fn NativityLLVMInitializeCodeGeneration() void; pub extern fn NativityLLVMGetTarget(target_triple_ptr: [*]const u8, target_triple_len: usize, message_ptr: *[*]const u8, message_len: *usize) ?*LLVM.Target; -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.OptimizationLevel, jit: bool) ?*LLVM.Target.Machine; +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 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; + + +pub extern fn LLVMInitializeAArch64TargetInfo() void; +pub extern fn LLVMInitializeAMDGPUTargetInfo() void; +pub extern fn LLVMInitializeARMTargetInfo() void; +pub extern fn LLVMInitializeAVRTargetInfo() void; +pub extern fn LLVMInitializeBPFTargetInfo() void; +pub extern fn LLVMInitializeHexagonTargetInfo() void; +pub extern fn LLVMInitializeLanaiTargetInfo() void; +pub extern fn LLVMInitializeMipsTargetInfo() void; +pub extern fn LLVMInitializeMSP430TargetInfo() void; +pub extern fn LLVMInitializeNVPTXTargetInfo() void; +pub extern fn LLVMInitializePowerPCTargetInfo() void; +pub extern fn LLVMInitializeRISCVTargetInfo() void; +pub extern fn LLVMInitializeSparcTargetInfo() void; +pub extern fn LLVMInitializeSystemZTargetInfo() void; +pub extern fn LLVMInitializeWebAssemblyTargetInfo() void; +pub extern fn LLVMInitializeX86TargetInfo() void; +pub extern fn LLVMInitializeXCoreTargetInfo() void; +pub extern fn LLVMInitializeXtensaTargetInfo() void; +pub extern fn LLVMInitializeM68kTargetInfo() void; +pub extern fn LLVMInitializeCSKYTargetInfo() void; +pub extern fn LLVMInitializeVETargetInfo() void; +pub extern fn LLVMInitializeARCTargetInfo() void; + +pub extern fn LLVMInitializeAArch64Target() void; +pub extern fn LLVMInitializeAMDGPUTarget() void; +pub extern fn LLVMInitializeARMTarget() void; +pub extern fn LLVMInitializeAVRTarget() void; +pub extern fn LLVMInitializeBPFTarget() void; +pub extern fn LLVMInitializeHexagonTarget() void; +pub extern fn LLVMInitializeLanaiTarget() void; +pub extern fn LLVMInitializeMipsTarget() void; +pub extern fn LLVMInitializeMSP430Target() void; +pub extern fn LLVMInitializeNVPTXTarget() void; +pub extern fn LLVMInitializePowerPCTarget() void; +pub extern fn LLVMInitializeRISCVTarget() void; +pub extern fn LLVMInitializeSparcTarget() void; +pub extern fn LLVMInitializeSystemZTarget() void; +pub extern fn LLVMInitializeWebAssemblyTarget() void; +pub extern fn LLVMInitializeX86Target() void; +pub extern fn LLVMInitializeXCoreTarget() void; +pub extern fn LLVMInitializeXtensaTarget() void; +pub extern fn LLVMInitializeM68kTarget() void; +pub extern fn LLVMInitializeVETarget() void; +pub extern fn LLVMInitializeCSKYTarget() void; +pub extern fn LLVMInitializeARCTarget() void; + +pub extern fn LLVMInitializeAArch64TargetMC() void; +pub extern fn LLVMInitializeAMDGPUTargetMC() void; +pub extern fn LLVMInitializeARMTargetMC() void; +pub extern fn LLVMInitializeAVRTargetMC() void; +pub extern fn LLVMInitializeBPFTargetMC() void; +pub extern fn LLVMInitializeHexagonTargetMC() void; +pub extern fn LLVMInitializeLanaiTargetMC() void; +pub extern fn LLVMInitializeMipsTargetMC() void; +pub extern fn LLVMInitializeMSP430TargetMC() void; +pub extern fn LLVMInitializeNVPTXTargetMC() void; +pub extern fn LLVMInitializePowerPCTargetMC() void; +pub extern fn LLVMInitializeRISCVTargetMC() void; +pub extern fn LLVMInitializeSparcTargetMC() void; +pub extern fn LLVMInitializeSystemZTargetMC() void; +pub extern fn LLVMInitializeWebAssemblyTargetMC() void; +pub extern fn LLVMInitializeX86TargetMC() void; +pub extern fn LLVMInitializeXCoreTargetMC() void; +pub extern fn LLVMInitializeXtensaTargetMC() void; +pub extern fn LLVMInitializeM68kTargetMC() void; +pub extern fn LLVMInitializeCSKYTargetMC() void; +pub extern fn LLVMInitializeVETargetMC() void; +pub extern fn LLVMInitializeARCTargetMC() void; + +pub extern fn LLVMInitializeAArch64AsmPrinter() void; +pub extern fn LLVMInitializeAMDGPUAsmPrinter() void; +pub extern fn LLVMInitializeARMAsmPrinter() void; +pub extern fn LLVMInitializeAVRAsmPrinter() void; +pub extern fn LLVMInitializeBPFAsmPrinter() void; +pub extern fn LLVMInitializeHexagonAsmPrinter() void; +pub extern fn LLVMInitializeLanaiAsmPrinter() void; +pub extern fn LLVMInitializeMipsAsmPrinter() void; +pub extern fn LLVMInitializeMSP430AsmPrinter() void; +pub extern fn LLVMInitializeNVPTXAsmPrinter() void; +pub extern fn LLVMInitializePowerPCAsmPrinter() void; +pub extern fn LLVMInitializeRISCVAsmPrinter() void; +pub extern fn LLVMInitializeSparcAsmPrinter() void; +pub extern fn LLVMInitializeSystemZAsmPrinter() void; +pub extern fn LLVMInitializeWebAssemblyAsmPrinter() void; +pub extern fn LLVMInitializeX86AsmPrinter() void; +pub extern fn LLVMInitializeXCoreAsmPrinter() void; +pub extern fn LLVMInitializeM68kAsmPrinter() void; +pub extern fn LLVMInitializeVEAsmPrinter() void; +pub extern fn LLVMInitializeARCAsmPrinter() void; + +pub extern fn LLVMInitializeAArch64AsmParser() void; +pub extern fn LLVMInitializeAMDGPUAsmParser() void; +pub extern fn LLVMInitializeARMAsmParser() void; +pub extern fn LLVMInitializeAVRAsmParser() void; +pub extern fn LLVMInitializeBPFAsmParser() void; +pub extern fn LLVMInitializeHexagonAsmParser() void; +pub extern fn LLVMInitializeLanaiAsmParser() void; +pub extern fn LLVMInitializeMipsAsmParser() void; +pub extern fn LLVMInitializeMSP430AsmParser() void; +pub extern fn LLVMInitializePowerPCAsmParser() void; +pub extern fn LLVMInitializeRISCVAsmParser() void; +pub extern fn LLVMInitializeSparcAsmParser() void; +pub extern fn LLVMInitializeSystemZAsmParser() void; +pub extern fn LLVMInitializeWebAssemblyAsmParser() void; +pub extern fn LLVMInitializeX86AsmParser() void; +pub extern fn LLVMInitializeXtensaAsmParser() void; +pub extern fn LLVMInitializeM68kAsmParser() void; +pub extern fn LLVMInitializeCSKYAsmParser() void; +pub extern fn LLVMInitializeVEAsmParser() void; diff --git a/lib/std/build.nat b/lib/std/build.nat index b1e35ca..679981e 100644 --- a/lib/std/build.nat +++ b/lib/std/build.nat @@ -3,12 +3,23 @@ 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 Executable = struct{ target: Target, main_source_path: [:0]const u8, link_libc: bool = false, name: [:0]const u8, c_source_files: []const [:0]const u8 = .{}.&, + optimization: Optimization = .none, + generate_debug_information: bool = true, const compile = fn(executable: Executable) *!void { const argument_count = std.start.argument_count; diff --git a/src/llvm/llvm.cpp b/src/llvm/llvm.cpp index 38adca8..00d29d8 100644 --- a/src/llvm/llvm.cpp +++ b/src/llvm/llvm.cpp @@ -1,6 +1,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/DIBuilder.h" @@ -934,6 +935,60 @@ extern "C" void NativityLLVMModuleSetTargetTriple(Module& module, const char* ta module.setTargetTriple(target_triple); } +extern "C" void NativityLLVMRunOptimizationPipeline(Module& module, TargetMachine& target_machine) +{ + // TODO: PGO + // TODO: CS profile + + 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.CallGraphProfile = false; + pipeline_tuning_options.UnifiedLTO = false; + + // TODO: instrumentation + + LoopAnalysisManager loop_analysis_manager; + FunctionAnalysisManager function_analysis_manager; + CGSCCAnalysisManager cgscc_analysis_manager; + ModuleAnalysisManager module_analysis_manager; + + PassBuilder pass_builder(&target_machine, pipeline_tuning_options); + // TODO: assignment tracking + // TODO: debug info preserve + // TODO: plugins? + + // TODO: target library analysis + + pass_builder.registerModuleAnalyses(module_analysis_manager); + pass_builder.registerCGSCCAnalyses(cgscc_analysis_manager); + pass_builder.registerFunctionAnalyses(function_analysis_manager); + pass_builder.registerLoopAnalyses(loop_analysis_manager); + pass_builder.crossRegisterProxies(loop_analysis_manager, function_analysis_manager, cgscc_analysis_manager, module_analysis_manager); + + ModulePassManager module_pass_manager; + + OptimizationLevel optimization_level = OptimizationLevel::O0; + bool thin_lto = false; + bool lto = false; + + // TODO: thin lto post-link + // TODO: instrument + if (thin_lto) { + // TODO + } else if (lto) { + // TODO + } else { + module_pass_manager = pass_builder.buildPerModuleDefaultPipeline(optimization_level, lto); + } + // TODO: if emit bitcode/IR + + module_pass_manager.run(module, module_analysis_manager); +} + extern "C" bool NativityLLVMModuleAddPassesToEmitFile(Module& module, TargetMachine& target_machine, const char* object_file_path_ptr, size_t object_file_path_len, CodeGenFileType codegen_file_type, bool disable_verify) { std::error_code error_code; @@ -944,6 +999,7 @@ extern "C" bool NativityLLVMModuleAddPassesToEmitFile(Module& module, TargetMach } legacy::PassManager pass; + // We invert the condition because LLVM conventions are just stupid if (target_machine.addPassesToEmitFile(pass, stream, nullptr, codegen_file_type, disable_verify)) { return false;