const lib = @import("lib.zig"); const Arena = lib.Arena; const assert = lib.assert; const os = lib.os; const builtin = @import("builtin"); const api = @import("llvm_api.zig"); /// This is a String which ABI-compatible with C++ pub const String = extern struct { pointer: ?[*]const u8 = null, length: usize = 0, pub fn from_slice(slice: []const u8) String { return String{ .pointer = slice.ptr, .length = slice.len, }; } pub fn to_slice(string: String) ?[]const u8 { if (string.length != 0) { return string.pointer.?[0..string.length]; } else { return null; } } }; pub const CodeModel = enum(u8) { none = 0, tiny = 1, small = 2, kernel = 3, medium = 4, large = 5, }; pub const RelocationModel = enum(u8) { default = 0, static = 1, pic = 2, dynamic_no_pic = 3, ropi = 4, rwpi = 5, ropi_rwpi = 6, }; pub const CodeGenerationOptimizationLevel = enum(u8) { none = 0, // -O0 less = 1, // -O1 default = 2, // -O2, -Os aggressive = 3, // -O3 }; pub const Target = opaque { /// This is ABI-compatible with C++ pub const Options = extern struct { flags0: packed struct(u64) { unsafe_fp_math: u1, no_infs_fp_math: u1, no_nans_fp_math: u1, no_trapping_fp_math: u1, no_signed_zeroes_fp_math: u1, approx_func_fp_match: u1, enable_aix_extended_altivec_abi: u1, honor_sign_dependent_rounding_fp_math: u1, no_zeroes_in_bss: u1, guaranteed_tail_call_optimization: u1, stack_symbol_ordering: u1, enable_fast_isel: u1, enable_global_isel: u1, global_isel_abort_mode: enum(u2) { disable = 0, enable = 1, disable_with_diag = 2, }, swift_async_frame_pointer: enum(u2) { deployment_based = 0, always = 1, never = 2, }, use_init_array: u1, disable_integrated_assembler: u1, function_sections: u1, data_sections: u1, ignore_xcoff_visibility: u1, xcoff_traceback_table: u1, unique_section_names: u1, unique_basic_block_section_names: u1, separate_named_sections: u1, trap_unreachable: u1, no_trap_after_noreturn: u1, tls_size: u8, emulated_tls: u1, enable_tls_descriptors: u1, enable_ipra: u1, emit_stack_size_section: u1, enable_machine_outliner: u1, enable_machine_function_splitter: u1, supports_default_outlining: u1, emit_address_significance_table: u1, bb_address_map: u1, bb_sections: enum(u3) { all = 0, list = 1, labels = 2, preset = 3, none = 4, }, emit_call_site_information: u1, supports_debug_entry_values: u1, enable_debug_entry_values: u1, value_tracking_variable_locations: u1, force_dwarf_frame_section: u1, xray_function_index: u1, debug_strict_dwarf: u1, hotpatch: u1, ppc_gen_scalar_mass_entries: u1, jmc_instrument: u1, enable_cfi_fixup: u1, mis_expect: u1, xcoff_read_only_pointers: u1, float_abi: enum(u2) { default = 0, soft = 1, hard = 2, }, thread_model: enum(u1) { posix = 0, single = 1, }, }, flags1: packed struct(u32) { fp_op_fusion_mode: enum(u2) { fast = 0, standard = 1, strict = 2, }, eabi_version: enum(u3) { unknown = 0, default = 1, eabi4 = 2, eabi5 = 3, gnu = 4, }, debugger_kind: enum(u3) { default = 0, gdb = 1, lldb = 2, sce = 3, dbx = 4, }, exception_handling: enum(u3) { none = 0, dwarf_cfi = 1, setjmp_longjmp = 2, arm = 3, win_eh = 4, wasm = 5, aix = 6, zos = 7, }, reserved: PaddingType = 0, }, loop_alignment: c_uint, binutils_version: [2]c_int, mc: MCTargetOptions, const padding_bit_count = 21; const PaddingType = @Type(.{ .int = .{ .signedness = .unsigned, .bits = padding_bit_count, }, }); comptime { assert(@sizeOf(Target.Options) == 136); assert(padding_bit_count == 21); } pub fn default() Target.Options { return .{ .binutils_version = .{ 0, 0 }, .flags0 = .{ .unsafe_fp_math = 0, .no_infs_fp_math = 0, .no_nans_fp_math = 0, .no_trapping_fp_math = 1, .no_signed_zeroes_fp_math = 0, .approx_func_fp_match = 0, .enable_aix_extended_altivec_abi = 0, .honor_sign_dependent_rounding_fp_math = 0, .no_zeroes_in_bss = 0, .guaranteed_tail_call_optimization = 0, .stack_symbol_ordering = 1, .enable_fast_isel = 0, .enable_global_isel = 0, .global_isel_abort_mode = .enable, .swift_async_frame_pointer = .always, .use_init_array = 0, .disable_integrated_assembler = 0, .function_sections = 0, .data_sections = 0, .ignore_xcoff_visibility = 0, .xcoff_traceback_table = 1, .unique_section_names = 1, .unique_basic_block_section_names = 0, .separate_named_sections = 0, .trap_unreachable = 0, .no_trap_after_noreturn = 0, .tls_size = 0, .emulated_tls = 0, .enable_tls_descriptors = 0, .enable_ipra = 0, .emit_stack_size_section = 0, .enable_machine_outliner = 0, .enable_machine_function_splitter = 0, .supports_default_outlining = 0, .emit_address_significance_table = 0, .bb_address_map = 0, .bb_sections = .none, .emit_call_site_information = 0, .supports_debug_entry_values = 0, .enable_debug_entry_values = 0, .value_tracking_variable_locations = 0, .force_dwarf_frame_section = 0, .xray_function_index = 1, .debug_strict_dwarf = 0, .hotpatch = 0, .ppc_gen_scalar_mass_entries = 0, .jmc_instrument = 0, .enable_cfi_fixup = 0, .mis_expect = 0, .xcoff_read_only_pointers = 0, .float_abi = .default, .thread_model = .posix, }, .flags1 = .{ .fp_op_fusion_mode = .standard, .eabi_version = .default, .debugger_kind = .default, .exception_handling = .none, }, .loop_alignment = 0, .mc = .{ .abi_name = .{}, .assembly_language = .{}, .split_dwarf_file = .{}, .as_secure_log_file = .{}, .argv0 = null, .argv_pointer = null, .argv_count = 0, .integrated_assembler_search_path_pointer = null, .integrated_assembler_search_path_count = 0, .flags = .{ .relax_all = 0, .no_exec_stack = 0, .fatal_warnings = 0, .no_warn = 0, .no_deprecated_warn = 0, .no_type_check = 0, .save_temp_labels = 0, .incremental_linker_compatible = 0, .fdpic = 0, .show_mc_encoding = 0, .show_mc_inst = 0, .asm_verbose = 0, .preserve_asm_comments = 1, .dwarf64 = 0, .crel = 0, .x86_relax_relocations = 1, .x86_sse2_avx = 0, .emit_dwarf_unwind = .default, .use_dwarf_directory = .default, .debug_compression_type = .none, .emit_compact_unwind_non_canonical = 0, .ppc_use_full_register_names = 0, }, }, }; } }; pub const Machine = opaque { /// This is ABI-compatible with C++ pub const Create = extern struct { target_options: Target.Options, cpu_triple: String, cpu_model: String, cpu_features: String, code_model: CodeModel, relocation_model: RelocationModel, optimization_level: CodeGenerationOptimizationLevel, jit: bool, reserved: [padding_byte_count]u8 = [1]u8{0} ** padding_byte_count, const padding_byte_count = 4; comptime { assert(@sizeOf(Create) == 192); assert(padding_byte_count == 4); } }; pub fn create(options: Create, error_message: *String) ?*Target.Machine { const target_machine = api.llvm_create_target_machine(&options, error_message); return target_machine; } }; }; pub const MCTargetOptions = extern struct { abi_name: String, assembly_language: String, split_dwarf_file: String, as_secure_log_file: String, argv0: ?[*:0]const u8, argv_pointer: ?[*]const String, argv_count: u64, integrated_assembler_search_path_pointer: ?[*]const String, integrated_assembler_search_path_count: u64, flags: packed struct(u32) { relax_all: u1, no_exec_stack: u1, fatal_warnings: u1, no_warn: u1, no_deprecated_warn: u1, no_type_check: u1, save_temp_labels: u1, incremental_linker_compatible: u1, fdpic: u1, show_mc_encoding: u1, show_mc_inst: u1, asm_verbose: u1, preserve_asm_comments: u1, dwarf64: u1, crel: u1, x86_relax_relocations: u1, x86_sse2_avx: u1, emit_dwarf_unwind: enum(u2) { always = 0, no_compact_unwind = 1, default = 2, }, use_dwarf_directory: enum(u2) { disable = 0, enable = 1, default = 2, }, debug_compression_type: enum(u2) { none = 0, zlib = 1, zstd = 2, }, emit_compact_unwind_non_canonical: u1, ppc_use_full_register_names: u1, reserved: PaddingType = 0, }, const padding_bit_count = 7; const PaddingType = @Type(.{ .int = .{ .signedness = .unsigned, .bits = 7, }, }); comptime { assert(@sizeOf(MCTargetOptions) == 112); assert(padding_bit_count == 7); } }; pub const OptimizationLevel = enum(u3) { O0 = 0, O1 = 1, O2 = 2, O3 = 3, Os = 4, Oz = 5, fn prefers_size(optimization_level: OptimizationLevel) bool { return switch (optimization_level) { .O0, .O1, .Os, .Oz => true, .O2, .O3 => false, }; } fn prefers_speed(optimization_level: OptimizationLevel) bool { return !prefers_size(optimization_level); } }; /// This is ABI-compatible with C++ pub const OptimizationPipelineOptions = packed struct(u64) { optimization_level: OptimizationLevel, debug_info: u1, loop_unrolling: u1, loop_interleaving: u1, loop_vectorization: u1, slp_vectorization: u1, merge_functions: u1, call_graph_profile: u1, unified_lto: u1, assignment_tracking: u1, verify_module: u1, reserved: PaddingType = 0, const padding_bit_count = 51; const PaddingType = @Type(.{ .int = .{ .signedness = .unsigned, .bits = padding_bit_count, }, }); comptime { assert(@sizeOf(OptimizationPipelineOptions) == @sizeOf(u64)); assert(padding_bit_count == 51); } const Create = packed struct { optimization_level: OptimizationLevel, debug_info: u1, }; pub fn default(create: Create) OptimizationPipelineOptions { const pref_speed = @intFromBool(create.optimization_level.prefers_speed()); return .{ .optimization_level = create.optimization_level, .debug_info = create.debug_info, .loop_unrolling = pref_speed, .loop_interleaving = pref_speed, .loop_vectorization = pref_speed, .slp_vectorization = pref_speed, .merge_functions = pref_speed, .call_graph_profile = 0, .unified_lto = 0, .assignment_tracking = create.debug_info, .verify_module = @intFromBool(lib.optimization_mode == .ReleaseSafe or lib.optimization_mode == .Debug), }; } }; /// This is ABI-compatible with C++ pub const CodeGenerationPipelineOptions = extern struct { output_dwarf_file_path: String, output_file_path: String, flags: packed struct(u64) { code_generation_file_type: enum(u2) { assembly_file = 0, object_file = 1, null = 2, }, optimize_when_possible: u1, verify_module: u1, reserved: PaddingType = 0, }, const padding_bit_count = 60; const PaddingType = @Type(.{ .int = .{ .signedness = .unsigned, .bits = padding_bit_count, }, }); comptime { assert(@sizeOf(CodeGenerationPipelineOptions) == 5 * @sizeOf(u64)); assert(padding_bit_count == 60); } }; pub const CodeGenerationPipelineResult = enum(u8) { success = 0, failed_to_create_file = 1, failed_to_add_emit_passes = 2, }; pub const Architecture = enum { X86, }; pub const TargetInitializerOptions = struct { asm_parser: bool = true, asm_printer: bool = true, disassembler: bool = false, }; const targets = [@typeInfo(Architecture).@"enum".fields.len]type{ api.get_initializer(.X86), }; pub const Context = opaque { pub const create = api.LLVMContextCreate; pub fn create_module(context: *Context, name: []const u8) *Module { return api.llvm_context_create_module(context, String.from_slice(name)); } pub const create_builder = api.LLVMCreateBuilderInContext; pub fn create_basic_block(context: *Context, name: []const u8, parent: *Function) *BasicBlock { return api.llvm_context_create_basic_block(context, String.from_slice(name), parent); } }; pub const BasicBlock = opaque {}; pub const Module = opaque { pub const create_di_builder = api.LLVMCreateDIBuilder; pub const set_target = api.llvm_module_set_target; pub const run_optimization_pipeline = api.llvm_module_run_optimization_pipeline; pub const run_code_generation_pipeline = api.llvm_module_run_code_generation_pipeline; pub fn to_string(module: *Module) []const u8 { return api.llvm_module_to_string(module).to_slice().?; } pub const FunctionCreate = struct { type: *Type.Function, linkage: LinkageType, address_space: c_uint = 0, name: []const u8, }; pub fn create_function(module: *Module, create: FunctionCreate) *Function { return api.llvm_module_create_function(module, create.type, create.linkage, create.address_space, String.from_slice(create.name)); } pub const GlobalCreate = struct { type: *Type, initial_value: *Constant, name: []const u8, before: ?*GlobalVariable = null, address_space: c_uint = 0, linkage: LinkageType, thread_local_mode: ThreadLocalMode = .none, is_constant: bool = false, externally_initialized: bool = false, }; pub fn create_global_variable(module: *Module, create: GlobalCreate) *GlobalVariable { return api.llvm_module_create_global_variable(module, create.type, create.is_constant, create.linkage, create.initial_value, String.from_slice(create.name), create.before, create.thread_local_mode, create.address_space, create.externally_initialized); } pub fn verify(module: *Module) VerifyResult { var result: VerifyResult = undefined; var string: String = undefined; result.success = api.llvm_module_verify(module, &string); result.error_message = string.to_slice(); return result; } }; pub const VerifyResult = struct { error_message: ?[]const u8, success: bool, }; pub const Builder = opaque { pub const position_at_end = api.LLVMPositionBuilderAtEnd; pub const create_ret = api.LLVMBuildRet; pub fn create_ret_void(builder: *Builder) void { builder.create_ret(null); } pub fn create_add(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildAdd(builder, left, right, ""); } pub fn create_sub(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildSub(builder, left, right, ""); } pub fn create_mul(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildMul(builder, left, right, ""); } pub fn create_sdiv(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildSDiv(builder, left, right, ""); } pub fn create_udiv(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildUDiv(builder, left, right, ""); } pub fn create_srem(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildSRem(builder, left, right, ""); } pub fn create_urem(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildURem(builder, left, right, ""); } pub fn create_shl(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildShl(builder, left, right, ""); } pub fn create_ashr(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildAShr(builder, left, right, ""); } pub fn create_lshr(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildLShr(builder, left, right, ""); } pub fn create_and(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildAnd(builder, left, right, ""); } pub fn create_or(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildOr(builder, left, right, ""); } pub fn create_xor(builder: *Builder, left: *Value, right: *Value) *Value { return api.LLVMBuildXor(builder, left, right, ""); } pub fn create_alloca(builder: *Builder, ty: *Type, name: []const u8) *Value { return api.llvm_builder_create_alloca(builder, ty, 0, String.from_slice(name)); } pub const create_store = api.LLVMBuildStore; pub fn create_load(builder: *Builder, ty: *Type, pointer: *Value) *Value { return api.LLVMBuildLoad2(builder, ty, pointer, ""); } pub fn clear_current_debug_location(builder: *Builder) void { return builder.set_current_debug_location(null); } pub const set_current_debug_location = api.LLVMSetCurrentDebugLocation2; }; pub const GlobalValue = opaque { pub const get_type = api.LLVMGlobalGetValueType; }; pub const GlobalVariable = opaque { pub const add_debug_info = api.llvm_global_variable_add_debug_info; pub fn to_value(global_variable: *GlobalVariable) *Value { return @ptrCast(global_variable); } }; pub const Function = opaque { pub fn get_type(function: *Function) *Type.Function { return function.to_global_value().get_type().to_function(); } pub fn to_value(function: *Function) *Value { return @ptrCast(function); } pub fn to_global_value(function: *Function) *GlobalValue { return @ptrCast(function); } pub fn verify(function: *Function) VerifyResult { var result: VerifyResult = undefined; var string: String = undefined; result.success = api.llvm_function_verify(function, &string); result.error_message = string.to_slice(); return result; } pub const set_subprogram = api.LLVMSetSubprogram; pub const get_subprogram = api.LLVMGetSubprogram; }; pub const Constant = opaque { pub fn to_value(constant: *Constant) *Value { return @ptrCast(constant); } pub const Integer = opaque { pub fn to_value(constant: *Constant.Integer) *Value { return @ptrCast(constant); } }; }; pub const Value = opaque { pub const get_type = api.LLVMTypeOf; pub fn is_constant(value: *Value) bool { return api.LLVMIsConstant(value) != 0; } pub fn to_constant(value: *Value) *Constant { assert(value.is_constant()); return @ptrCast(value); } }; pub const DI = struct { pub const Builder = opaque { pub fn create_file(builder: *DI.Builder, file_name: []const u8, directory: []const u8) *File { return api.LLVMDIBuilderCreateFile(builder, String.from_slice(file_name), String.from_slice(directory)); } pub fn create_compile_unit(builder: *DI.Builder, file: *DI.File, optimized: bool) *DI.CompileUnit { return api.LLVMDIBuilderCreateCompileUnit(builder, .C17, file, String.from_slice("bloat buster"), @intFromBool(optimized), String{}, 0, String{}, .full, 0, 0, @intFromBool(optimized), String{}, String{}); } pub const finalize = api.LLVMDIBuilderFinalize; pub fn create_subroutine_type(builder: *DI.Builder, file: *DI.File, parameter_types: []const *DI.Type, flags: DI.Flags) *DI.Type.Subroutine { return api.LLVMDIBuilderCreateSubroutineType(builder, file, parameter_types.ptr, @intCast(parameter_types.len), flags); } pub fn create_function(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, linkage_name: []const u8, file: *DI.File, line_number: c_uint, subroutine_type: *DI.Type.Subroutine, local_to_unit: bool, is_definition: bool, scope_line: c_uint, flags: DI.Flags, is_optimized: bool) *DI.Subprogram { return api.LLVMDIBuilderCreateFunction(builder, scope, String.from_slice(name), String.from_slice(linkage_name), file, line_number, subroutine_type, @intFromBool(local_to_unit), @intFromBool(is_definition), scope_line, flags, @intFromBool(is_optimized)); } pub fn create_basic_type(builder: *DI.Builder, name: []const u8, bit_count: u64, dwarf_type: Dwarf.Type, flags: DI.Flags) *DI.Type { return api.LLVMDIBuilderCreateBasicType(builder, name.ptr, name.len, bit_count, dwarf_type, flags); } pub const finalize_subprogram = api.LLVMDIBuilderFinalizeSubprogram; pub fn create_expression(builder: *DI.Builder, slice: []const u64) *DI.Expression { return api.LLVMDIBuilderCreateExpression(builder, slice.ptr, slice.len); } pub fn null_expression(builder: *DI.Builder) *DI.Expression { return api.LLVMDIBuilderCreateExpression(builder, null, 0); } pub fn create_auto_variable(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, auto_type: *DI.Type, always_preserve: bool, flags: DI.Flags, alignment_in_bits: u32) *DI.LocalVariable { return api.LLVMDIBuilderCreateAutoVariable(builder, scope, name.ptr, name.len, file, line, auto_type, @intFromBool(always_preserve), flags, alignment_in_bits); } pub const insert_declare_record_at_end = api.LLVMDIBuilderInsertDeclareRecordAtEnd; pub fn create_global_variable(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, linkage_name: []const u8, file: *DI.File, line: c_uint, global_type: *DI.Type, local_to_unit: bool, expression: *DI.Expression, align_in_bits: u32) *DI.GlobalVariableExpression { const declaration: ?*DI.Metadata = null; return api.LLVMDIBuilderCreateGlobalVariableExpression(builder, scope, name.ptr, name.len, linkage_name.ptr, linkage_name.len, file, line, global_type, @intFromBool(local_to_unit), expression, declaration, align_in_bits); } // pub extern fn LLVMDIBuilderCreateGlobalVariableExpression(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, linkage_name_pointer: [*]const u8, linkage_name_length: usize, file: *llvm.DI.File, line: c_uint, global_type: *llvm.DI.Type, local_to_unit: Bool, expression: *llvm.DI.Expression, declaration: ?*llvm.DI.Metadata, align_in_bits: u32) *llvm.DI.GlobalVariableExpression; }; pub const create_debug_location = api.LLVMDIBuilderCreateDebugLocation; pub const CompileUnit = opaque { pub fn to_scope(compile_unit: *DI.CompileUnit) *DI.Scope { return @ptrCast(compile_unit); } }; pub const File = opaque {}; pub const Scope = opaque {}; pub const Subprogram = opaque {}; pub const Expression = opaque {}; pub const GlobalVariableExpression = opaque {}; pub const LocalVariable = opaque {}; pub const Location = opaque {}; pub const Metadata = opaque {}; pub const Record = opaque {}; pub const Type = opaque { pub const Subroutine = opaque {}; }; pub const Flags = packed struct(u32) { visibility: Visibility = .none, forward_declaration: bool = false, apple_block: bool = false, block_by_ref_struct: bool = false, virtual: bool = false, artificial: bool = false, explicit: bool = false, prototyped: bool = false, objective_c_class_complete: bool = false, object_pointer: bool = false, vector: bool = false, static_member: bool = false, lvalue_reference: bool = false, rvalue_reference: bool = false, reserved: bool = false, inheritance: Inheritance = .none, introduced_virtual: bool = false, bit_field: bool = false, no_return: bool = false, type_pass_by_value: bool = false, type_pass_by_reference: bool = false, enum_class: bool = false, thunk: bool = false, non_trivial: bool = false, big_endian: bool = false, little_endian: bool = false, all_calls_described: bool = false, _: u3 = 0, const Visibility = enum(u2) { none = 0, private = 1, protected = 2, public = 3, }; const Inheritance = enum(u2) { none = 0, single = 1, multiple = 2, virtual = 3, }; }; }; pub const Type = opaque { pub const is_function = api.llvm_type_is_function; pub const is_integer = api.llvm_type_is_integer; pub fn to_function(t: *Type) *Type.Function { assert(t.is_function()); return @ptrCast(t); } pub fn to_integer(t: *Type) *Type.Integer { assert(t.is_integer()); return @ptrCast(t); } pub const Function = opaque { pub const get_return_type = api.LLVMGetReturnType; pub fn get(return_type: *Type, parameter_types: []const *Type, is_var_args: bool) *Type.Function { return api.LLVMFunctionType(return_type, parameter_types.ptr, @intCast(parameter_types.len), @intFromBool(is_var_args)); } }; pub const Integer = opaque { pub const get_constant = api.LLVMConstInt; pub fn to_type(integer: *Type.Integer) *Type { return @ptrCast(integer); } pub const get_bit_count = api.llvm_integer_type_get_bit_count; }; }; pub const Dwarf = struct { pub const Type = enum(c_uint) { void = 0x0, address = 0x1, boolean = 0x2, complex_float = 0x3, float = 0x4, signed = 0x5, signed_char = 0x6, unsigned = 0x7, unsigned_char = 0x8, // DWARF 3. imaginary_float = 0x9, packed_decimal = 0xa, numeric_string = 0xb, edited = 0xc, signed_fixed = 0xd, unsigned_fixed = 0xe, decimal_float = 0xf, // DWARF 4. UTF = 0x10, // DWARF 5. UCS = 0x11, ASCII = 0x12, // HP extensions. HP_float80 = 0x80, // Floating-point (80 bit). HP_complex_float80 = 0x81, // Complex floating-point (80 bit). HP_float128 = 0x82, // Floating-point (128 bit). HP_complex_float128 = 0x83, // Complex fp (128 bit). HP_floathpintel = 0x84, // Floating-point (82 bit IA64). HP_imaginary_float80 = 0x85, HP_imaginary_float128 = 0x86, HP_VAX_float = 0x88, // F or G floating. HP_VAX_float_d = 0x89, // D floating. HP_packed_decimal = 0x8a, // Cobol. HP_zoned_decimal = 0x8b, // Cobol. HP_edited = 0x8c, // Cobol. HP_signed_fixed = 0x8d, // Cobol. HP_unsigned_fixed = 0x8e, // Cobol. HP_VAX_complex_float = 0x8f, // F or G floating complex. HP_VAX_complex_float_d = 0x90, // D floating complex. }; pub const EmissionKind = enum(c_int) { none, full, line_tables_only, }; pub const SourceLanguage = enum(c_int) { C89, C, Ada83, C_plus_plus, Cobol74, Cobol85, Fortran77, Fortran90, Pascal83, Modula2, // New in DWARF v3: Java, C99, Ada95, Fortran95, PLI, ObjC, ObjC_plus_plus, UPC, D, // New in DWARF v4: Python, // New in DWARF v5: OpenCL, Go, Modula3, Haskell, C_plus_plus_03, C_plus_plus_11, OCaml, Rust, C11, Swift, Julia, Dylan, C_plus_plus_14, Fortran03, Fortran08, RenderScript, BLISS, Kotlin, Zig, Crystal, C_plus_plus_17, C_plus_plus_20, C17, Fortran18, Ada2005, Ada2012, HIP, Assembly, C_sharp, Mojo, GLSL, GLSL_ES, HLSL, OpenCL_CPP, CPP_for_OpenCL, SYCL, Ruby, Move, Hylo, // Vendor extensions: Mips_Assembler, GOOGLE_RenderScript, BORLAND_Delphi, }; }; pub const LinkageType = enum(c_int) { ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, LinkOnceODRLinkage, WeakAnyLinkage, WeakODRLinkage, AppendingLinkage, InternalLinkage, PrivateLinkage, ExternalWeakLinkage, CommonLinkage, }; pub const ThreadLocalMode = enum(c_uint) { none = 0, }; pub const lld = struct { pub const Result = extern struct { stdout: String, stderr: String, success: bool, }; }; pub const Thread = struct { context: *Context, builder: *Builder, i1: Integer, i8: Integer, i16: Integer, i32: Integer, i64: Integer, i128: Integer, pub const Integer = struct { type: *Type.Integer, zero: *Constant.Integer, }; pub fn initialize(thread: *Thread) void { const context = Context.create(); const type_i1 = api.LLVMInt1TypeInContext(context); const type_i8 = api.LLVMInt8TypeInContext(context); const type_i16 = api.LLVMInt16TypeInContext(context); const type_i32 = api.LLVMInt32TypeInContext(context); const type_i64 = api.LLVMInt64TypeInContext(context); const type_i128 = api.LLVMInt128TypeInContext(context); const zero_i1 = type_i1.get_constant(0, 0); const zero_i8 = type_i8.get_constant(0, 0); const zero_i16 = type_i16.get_constant(0, 0); const zero_i32 = type_i32.get_constant(0, 0); const zero_i64 = type_i64.get_constant(0, 0); const zero_i128 = type_i128.get_constant(0, 0); thread.* = .{ .context = context, .builder = context.create_builder(), .i1 = .{ .type = type_i1, .zero = zero_i1, }, .i8 = .{ .type = type_i8, .zero = zero_i8, }, .i16 = .{ .type = type_i16, .zero = zero_i16, }, .i32 = .{ .type = type_i32, .zero = zero_i32, }, .i64 = .{ .type = type_i64, .zero = zero_i64, }, .i128 = .{ .type = type_i128, .zero = zero_i128, }, }; } }; pub const Global = struct { threads: []Thread, host_triple: []const u8, host_cpu_model: []const u8, host_cpu_features: []const u8, }; pub var global: Global = undefined; pub var initialized = false; // This is meant to call globally, only once per execution pub fn initialize_all() void { assert(!initialized); defer initialized = true; inline for (targets) |target| { target.initialize(.{}); } global = .{ .threads = lib.global.arena.allocate(Thread, lib.global.thread_count), .host_triple = api.llvm_default_target_triple().to_slice() orelse unreachable, .host_cpu_model = api.llvm_host_cpu_name().to_slice() orelse unreachable, .host_cpu_features = api.llvm_host_cpu_features().to_slice() orelse unreachable, }; } const LldArgvBuilder = struct { buffer: [1024]?[*:0]const u8 = undefined, count: usize = 0, pub fn add(builder: *LldArgvBuilder, arg: [*:0]const u8) void { builder.buffer[builder.count] = arg; builder.count += 1; } pub fn flush(builder: *LldArgvBuilder) [:null]const ?[*:0]const u8 { builder.buffer[builder.count] = null; return builder.buffer[0..builder.count :null]; } }; pub fn default_initialize() *Thread { assert(lib.GlobalState.initialized); if (!initialized) { initialize_all(); } const thread = &global.threads[0]; thread.initialize(); return thread; } pub const GenerateObject = struct { path: []const u8, target_triple: []const u8, cpu_model: []const u8, cpu_features: []const u8, target_options: Target.Options, }; pub const ObjectGenerate = struct { path: []const u8, optimization_level: ?OptimizationLevel, debug_info: bool, optimize_when_possible: u1, }; pub fn object_generate(module: *Module, target_machine: *Target.Machine, generate: ObjectGenerate) CodeGenerationPipelineResult { module.set_target(target_machine); if (generate.optimization_level) |optimization_level| { module.run_optimization_pipeline(target_machine, OptimizationPipelineOptions.default(.{ .optimization_level = optimization_level, .debug_info = @intFromBool(generate.debug_info) })); } const result = module.run_code_generation_pipeline(target_machine, CodeGenerationPipelineOptions{ .output_file_path = String.from_slice(generate.path), .output_dwarf_file_path = .{}, .flags = .{ .code_generation_file_type = .object_file, .optimize_when_possible = generate.optimize_when_possible, .verify_module = @intFromBool(lib.optimization_mode == .Debug or lib.optimization_mode == .ReleaseSafe), }, }); return result; } pub const LinkOptions = struct { objects: []const [:0]const u8, output_path: [:0]const u8, }; pub fn link(arena: *Arena, options: LinkOptions) lld.Result { var arg_builder = LldArgvBuilder{}; arg_builder.add("ld.lld"); arg_builder.add("--error-limit=0"); arg_builder.add("-o"); arg_builder.add(options.output_path); for (options.objects) |object| { arg_builder.add(object); } const library_paths = [_][:0]const u8{ "/usr/lib", "/usr/lib/x86_64-linux-gnu" }; const scrt1_object_directory_path = inline for (library_paths) |library_path| { const scrt1_path = library_path ++ "/" ++ "Scrt1.o"; const file = lib.os.File.open(scrt1_path, .{ .read = 1 }, .{}); if (file.is_valid()) { file.close(); break library_path; } } else { lib.print_string_stderr("Failed to find directory for Scrt1.o\n"); lib.os.abort(); }; arg_builder.add(arena.join_string(&.{ "-L", scrt1_object_directory_path })); const link_libcpp = false; if (link_libcpp) { arg_builder.add("-lstdc++"); } const link_libc = true; const dynamic_linker = true; if (dynamic_linker) { arg_builder.add("-dynamic-linker"); const dynamic_linker_path = "/usr/lib64/ld-linux-x86-64.so.2"; arg_builder.add(dynamic_linker_path); } if (link_libc) { const scrt1_path = arena.join_string(&.{ scrt1_object_directory_path, "/Scrt1.o" }); arg_builder.add(scrt1_path); arg_builder.add("-lc"); } const lld_args = arg_builder.flush(); const lld_result = api.lld_elf_link(lld_args.ptr, lld_args.len, true, false); const success = lld_result.success and lld_result.stderr.length == 0; if (!success) { for (lld_args) |lld_arg| { lib.print_string_stderr(lib.cstring.to_slice(lld_arg.?)); lib.print_string_stderr(" "); } lib.print_string_stderr("\n"); if (lld_result.stdout.length != 0) { lib.print_string_stderr(lld_result.stdout.to_slice() orelse unreachable); } if (lld_result.stderr.length != 0) { lib.print_string_stderr(lld_result.stderr.to_slice() orelse unreachable); } } return lld_result; }