Write some LLVM optimization pipeline stub

This commit is contained in:
David Gonzalez Martin 2024-04-09 20:51:06 -06:00
parent 636e6c0be2
commit 60abe3f9d5
4 changed files with 209 additions and 117 deletions

View File

@ -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]);
// }
}

View File

@ -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;

View File

@ -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;

View File

@ -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;