diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 2db2231..9e65361 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -18,6 +18,8 @@ const starts_with_slice = library.starts_with_slice; const PinnedArray = library.PinnedArray; const PinnedArrayAdvanced = library.PinnedArrayAdvanced; const PinnedHashMap = library.PinnedHashMap; +const realpath = library.realpath; +const self_exe_path = library.self_exe_path; const span = library.span; const format_int = library.format_int; const my_hash = library.my_hash; @@ -3087,19 +3089,6 @@ fn createUnit(context: *const Context, arguments: struct { return unit; } -pub fn self_exe_path(arena: *Arena) ![]const u8 { - var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - return try arena.duplicate_bytes(try std.fs.selfExePath(&buffer)); -} - -pub fn realpath(arena: *Arena, dir: std.fs.Dir, relative_path: []const u8) ![]const u8 { - var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const stack_realpath = try dir.realpath(relative_path, &buffer); - const heap_realpath = try arena.new_array(u8, stack_realpath.len); - @memcpy(heap_realpath, stack_realpath); - return heap_realpath; -} - pub const ContainerType = enum { @"struct", @"enum", diff --git a/bootstrap/backend/llvm_bindings.zig b/bootstrap/backend/llvm_bindings.zig index 28ea45d..4171280 100644 --- a/bootstrap/backend/llvm_bindings.zig +++ b/bootstrap/backend/llvm_bindings.zig @@ -1,71 +1,72 @@ -const llvm = @import("llvm.zig"); -const LLVM = llvm.LLVM; -pub extern fn NativityLLVMCreateContext() ?*LLVM.Context; -pub extern fn NativityLLVMCreateModule(module_name_ptr: [*:0]const u8, module_name_len: usize, context: *LLVM.Context) ?*LLVM.Module; -pub extern fn NativityLLVMCreateBuilder(context: *LLVM.Context) ?*LLVM.Builder; -pub extern fn NativityLLVMGetFunctionType(return_type: *LLVM.Type, argument_type_ptr: [*]const *LLVM.Type, argument_type_len: usize, is_var_args: bool) ?*LLVM.Type.Function; +const compiler = @import("../compiler.zig"); +const LLVM = compiler.LLVM; + +pub extern fn NativityLLVMCreateContext() *LLVM.Context; +pub extern fn NativityLLVMCreateModule(module_name_ptr: [*]const u8, module_name_len: usize, context: *LLVM.Context) *LLVM.Module; +pub extern fn NativityLLVMCreateBuilder(context: *LLVM.Context) *LLVM.Builder; +pub extern fn NativityLLVMGetFunctionType(return_type: *LLVM.Type, argument_type_ptr: [*]const *LLVM.Type, argument_type_len: usize, is_var_args: bool) *LLVM.Type.Function; pub extern fn NativityLLVMFunctionTypeGetArgumentType(function_type: *LLVM.Type.Function, argument_index: c_uint) *LLVM.Type; -pub extern fn NativityLLVMGetIntegerType(context: *LLVM.Context, bit_count: u32) ?*LLVM.Type.Integer; -pub extern fn NativityLLVMGetPointerType(context: *LLVM.Context, address_space: u32) ?*LLVM.Type.Pointer; +pub extern fn NativityLLVMGetIntegerType(context: *LLVM.Context, bit_count: u32) *LLVM.Type.Integer; +pub extern fn NativityLLVMGetPointerType(context: *LLVM.Context, address_space: u32) *LLVM.Type.Pointer; pub extern fn NativityLLVMPointerTypeGetNull(pointer_type: *LLVM.Type.Pointer) *LLVM.Value.Constant.PointerNull; -pub extern fn NativityLLVMGetArrayType(element_type: *LLVM.Type, element_count: u64) ?*LLVM.Type.Array; -pub extern fn NativityLLVMGetStructType(context: *LLVM.Context, type_ptr: [*]const *LLVM.Type, type_count: usize, is_packed: bool) ?*LLVM.Type.Struct; -pub extern fn NativityLLVMConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_count: usize) ?*LLVM.Value.Constant; +pub extern fn NativityLLVMGetArrayType(element_type: *LLVM.Type, element_count: u64) *LLVM.Type.Array; +pub extern fn NativityLLVMGetStructType(context: *LLVM.Context, type_ptr: [*]const *LLVM.Type, type_count: usize, is_packed: bool) *LLVM.Type.Struct; +pub extern fn NativityLLVMConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_count: usize) *LLVM.Value.Constant; pub extern fn NativityLLVMModuleGetFunction(module: *LLVM.Module, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Constant.Function; -pub extern fn NativityLLVModuleCreateFunction(module: *LLVM.Module, function_type: *LLVM.Type.Function, linkage: LLVM.Linkage, address_space: c_uint, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Constant.Function; -pub extern fn NativityLLVMModuleCreateDebugInfoBuilder(module: *LLVM.Module) ?*LLVM.DebugInfo.Builder; -pub extern fn NativityLLVMDebugInfoBuilderCreateFile(builder: *LLVM.DebugInfo.Builder, filename_ptr: [*]const u8, filename_len: usize, directory_ptr: [*]const u8, directory_len: usize) ?*LLVM.DebugInfo.File; -pub extern fn NativityLLVMDebugInfoBuilderCreateCompileUnit(builder: *LLVM.DebugInfo.Builder, language: LLVM.DebugInfo.Language, file: *LLVM.DebugInfo.File, producer_ptr: [*]const u8, producer_len: usize, is_optimized: bool, flags_ptr: [*]const u8, flags_len: usize, runtime_version: c_uint, split_name_ptr: [*]const u8, split_name_len: usize, debug_info_emission_kind: LLVM.DebugInfo.CompileUnit.EmissionKind, DWOId: u64, split_debug_inlining: bool, debug_info_for_profiling: bool, debug_info_name_table_kind: LLVM.DebugInfo.CompileUnit.NameTableKind, ranges_base_address: bool, sysroot_ptr: [*]const u8, sysroot_len: usize, sdk_ptr: [*]const u8, sdk_len: usize) ?*LLVM.DebugInfo.CompileUnit; -pub extern fn NativityLLVMDebugInfoBuilderCreateFunction(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, linkage_name_ptr: [*]const u8, linkage_name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type.Subroutine, scope_line: c_uint, flags: LLVM.DebugInfo.Node.Flags, subprogram_flags: LLVM.DebugInfo.Subprogram.Flags, declaration: ?*LLVM.DebugInfo.Subprogram) ?*LLVM.DebugInfo.Subprogram; -pub extern fn NativityLLVMDebugInfoBuilderCreateSubroutineType(builder: *LLVM.DebugInfo.Builder, parameter_types_ptr: [*]const *LLVM.DebugInfo.Type, parameter_type_count: usize, flags: LLVM.DebugInfo.Node.Flags, calling_convention: LLVM.DebugInfo.CallingConvention) ?*LLVM.DebugInfo.Type.Subroutine; -pub extern fn NativityLLVMDebugInfoBuilderCreateLexicalBlock(builder: *LLVM.DebugInfo.Builder, parent_scope: *LLVM.DebugInfo.Scope, parent_file: *LLVM.DebugInfo.File, line: c_uint, column: c_uint) ?*LLVM.DebugInfo.LexicalBlock; +pub extern fn NativityLLVModuleCreateFunction(module: *LLVM.Module, function_type: *LLVM.Type.Function, linkage: LLVM.Linkage, address_space: c_uint, name_ptr: [*]const u8, name_len: usize) *LLVM.Value.Constant.Function; +pub extern fn NativityLLVMModuleCreateDebugInfoBuilder(module: *LLVM.Module) *LLVM.DebugInfo.Builder; +pub extern fn NativityLLVMDebugInfoBuilderCreateFile(builder: *LLVM.DebugInfo.Builder, filename_ptr: [*]const u8, filename_len: usize, directory_ptr: [*]const u8, directory_len: usize) *LLVM.DebugInfo.File; +pub extern fn NativityLLVMDebugInfoBuilderCreateCompileUnit(builder: *LLVM.DebugInfo.Builder, language: LLVM.DebugInfo.Language, file: *LLVM.DebugInfo.File, producer_ptr: [*]const u8, producer_len: usize, is_optimized: bool, flags_ptr: [*]const u8, flags_len: usize, runtime_version: c_uint, split_name_ptr: [*]const u8, split_name_len: usize, debug_info_emission_kind: LLVM.DebugInfo.CompileUnit.EmissionKind, DWOId: u64, split_debug_inlining: bool, debug_info_for_profiling: bool, debug_info_name_table_kind: LLVM.DebugInfo.CompileUnit.NameTableKind, ranges_base_address: bool, sysroot_ptr: [*]const u8, sysroot_len: usize, sdk_ptr: [*]const u8, sdk_len: usize) *LLVM.DebugInfo.CompileUnit; +pub extern fn NativityLLVMDebugInfoBuilderCreateFunction(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, linkage_name_ptr: [*]const u8, linkage_name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type.Subroutine, scope_line: c_uint, flags: LLVM.DebugInfo.Node.Flags, subprogram_flags: LLVM.DebugInfo.Subprogram.Flags, declaration: ?*LLVM.DebugInfo.Subprogram) *LLVM.DebugInfo.Subprogram; +pub extern fn NativityLLVMDebugInfoBuilderCreateSubroutineType(builder: *LLVM.DebugInfo.Builder, parameter_types_ptr: [*]const *LLVM.DebugInfo.Type, parameter_type_count: usize, flags: LLVM.DebugInfo.Node.Flags, calling_convention: LLVM.DebugInfo.CallingConvention) *LLVM.DebugInfo.Type.Subroutine; +pub extern fn NativityLLVMDebugInfoBuilderCreateLexicalBlock(builder: *LLVM.DebugInfo.Builder, parent_scope: *LLVM.DebugInfo.Scope, parent_file: *LLVM.DebugInfo.File, line: c_uint, column: c_uint) *LLVM.DebugInfo.LexicalBlock; pub extern fn NativityLLVMDebugInfoBuilderCreateExpression(builder: *LLVM.DebugInfo.Builder, address: [*]const u64, length: usize) *LLVM.DebugInfo.Expression; -pub extern fn NativityLLVMDebugInfoBuilderCreateGlobalVariableExpression(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, linkage_name_ptr: [*]const u8, linkage_name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, is_local_to_unit: bool, is_defined: bool, expression: ?*LLVM.DebugInfo.Expression, declaration: ?*LLVM.Metadata.Node, template_parameters: ?*LLVM.Metadata.Tuple, alignment: u32) ?*LLVM.DebugInfo.GlobalVariableExpression; -pub extern fn NativityLLVMDebugInfoBuilderCreateParameterVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, argument_index: c_uint, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags) ?*LLVM.DebugInfo.LocalVariable; -pub extern fn NativityLLVMDebugInfoBuilderCreateAutoVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags, alignment: u32) ?*LLVM.DebugInfo.LocalVariable; // 0 means 1 << 0 (alignment of 1) -pub extern fn NativityLLVMDebugInfoBuilderInsertDeclare(builder: *LLVM.DebugInfo.Builder, pointer: *LLVM.Value, local_variable: *LLVM.DebugInfo.LocalVariable, context: *LLVM.Context, line: c_uint, column: c_uint, scope: *LLVM.DebugInfo.Scope, basic_block: *LLVM.Value.BasicBlock) ?*LLVM.Value.Instruction; +pub extern fn NativityLLVMDebugInfoBuilderCreateGlobalVariableExpression(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, linkage_name_ptr: [*]const u8, linkage_name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, is_local_to_unit: bool, is_defined: bool, expression: ?*LLVM.DebugInfo.Expression, declaration: ?*LLVM.Metadata.Node, template_parameters: ?*LLVM.Metadata.Tuple, alignment: u32) *LLVM.DebugInfo.GlobalVariableExpression; +pub extern fn NativityLLVMDebugInfoBuilderCreateParameterVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, argument_index: c_uint, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags) *LLVM.DebugInfo.LocalVariable; +pub extern fn NativityLLVMDebugInfoBuilderCreateAutoVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags, alignment: u32) *LLVM.DebugInfo.LocalVariable; // 0 means 1 << 0 (alignment of 1) +pub extern fn NativityLLVMDebugInfoBuilderInsertDeclare(builder: *LLVM.DebugInfo.Builder, pointer: *LLVM.Value, local_variable: *LLVM.DebugInfo.LocalVariable, context: *LLVM.Context, line: c_uint, column: c_uint, scope: *LLVM.DebugInfo.Scope, basic_block: *LLVM.Value.BasicBlock) *LLVM.Value.Instruction; -pub extern fn NativityLLVMDebugInfoBuilderCreateBasicType(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, bit_count: u64, dwarf_encoding: LLVM.DebugInfo.AttributeType, flags: LLVM.DebugInfo.Node.Flags) ?*LLVM.DebugInfo.Type; -pub extern fn NativityLLVMDebugInfoBuilderCreatePointerType(builder: *LLVM.DebugInfo.Builder, element_type: *LLVM.DebugInfo.Type, pointer_bit_count: u64, alignment: u32, name_ptr: [*]const u8, name_len: usize) ?*LLVM.DebugInfo.Type.Derived; -pub extern fn NativityLLVMDebugInfoBuilderCreateStructType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: ?*LLVM.DebugInfo.File, line_number: c_uint, bit_count: u64, alignment: u32, flags: LLVM.DebugInfo.Node.Flags, derived_from: ?*LLVM.DebugInfo.Type, element_type_ptr: [*]const *LLVM.DebugInfo.Type, element_type_count: usize, forward_declaration: ?*LLVM.DebugInfo.Type.Composite) ?*LLVM.DebugInfo.Type.Composite; -pub extern fn NativityLLVMDebugInfoBuilderCreateArrayType(builder: *LLVM.DebugInfo.Builder, bit_size: u64, alignment: u32, type: *LLVM.DebugInfo.Type, element_count: usize) ?*LLVM.DebugInfo.Type.Composite; -pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerationType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line: c_uint, bit_size: u64, alignment: u32, enumerator_ptr: [*]const *LLVM.DebugInfo.Type.Enumerator, enumerator_count: usize, underlying_type: *LLVM.DebugInfo.Type) ?*LLVM.DebugInfo.Type.Composite; -pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerator(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, value: u64, is_unsigned: bool) ?*LLVM.DebugInfo.Type.Enumerator; -pub extern fn NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType(builder: *LLVM.DebugInfo.Builder, tag: c_uint, name_ptr: [*]const u8, name_len: usize, scope: ?*LLVM.DebugInfo.Scope, file: ?*LLVM.DebugInfo.File, line: c_uint) ?*LLVM.DebugInfo.Type.Composite; +pub extern fn NativityLLVMDebugInfoBuilderCreateBasicType(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, bit_count: u64, dwarf_encoding: LLVM.DebugInfo.AttributeType, flags: LLVM.DebugInfo.Node.Flags) *LLVM.DebugInfo.Type; +pub extern fn NativityLLVMDebugInfoBuilderCreatePointerType(builder: *LLVM.DebugInfo.Builder, element_type: *LLVM.DebugInfo.Type, pointer_bit_count: u64, alignment: u32, name_ptr: [*]const u8, name_len: usize) *LLVM.DebugInfo.Type.Derived; +pub extern fn NativityLLVMDebugInfoBuilderCreateStructType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: ?*LLVM.DebugInfo.File, line_number: c_uint, bit_count: u64, alignment: u32, flags: LLVM.DebugInfo.Node.Flags, derived_from: ?*LLVM.DebugInfo.Type, element_type_ptr: [*]const *LLVM.DebugInfo.Type, element_type_count: usize, forward_declaration: ?*LLVM.DebugInfo.Type.Composite) *LLVM.DebugInfo.Type.Composite; +pub extern fn NativityLLVMDebugInfoBuilderCreateArrayType(builder: *LLVM.DebugInfo.Builder, bit_size: u64, alignment: u32, type: *LLVM.DebugInfo.Type, element_count: usize) *LLVM.DebugInfo.Type.Composite; +pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerationType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line: c_uint, bit_size: u64, alignment: u32, enumerator_ptr: [*]const *LLVM.DebugInfo.Type.Enumerator, enumerator_count: usize, underlying_type: *LLVM.DebugInfo.Type) *LLVM.DebugInfo.Type.Composite; +pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerator(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, value: u64, is_unsigned: bool) *LLVM.DebugInfo.Type.Enumerator; +pub extern fn NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType(builder: *LLVM.DebugInfo.Builder, tag: c_uint, name_ptr: [*]const u8, name_len: usize, scope: ?*LLVM.DebugInfo.Scope, file: ?*LLVM.DebugInfo.File, line: c_uint) *LLVM.DebugInfo.Type.Composite; pub extern fn NativityLLVMDebugInfoBuilderCreateMemberType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: ?*LLVM.DebugInfo.File, line_number: c_uint, bit_size: u64, alignment: u32, bit_offset: u64, flags: LLVM.DebugInfo.Node.Flags, type: *LLVM.DebugInfo.Type) *LLVM.DebugInfo.Type.Derived; pub extern fn NativityLLVMDebugInfoBuilderCompositeTypeReplaceTypes(builder: *LLVM.DebugInfo.Builder, type: *LLVM.DebugInfo.Type.Composite, element_type_ptr: [*]const *LLVM.DebugInfo.Type, element_type_count: usize) void; pub extern fn NativityLLLVMDITypeIsResolved(type: *LLVM.DebugInfo.Type) bool; pub extern fn NativityLLVMDebugInfoBuilderFinalizeSubprogram(builder: *LLVM.DebugInfo.Builder, subprogram: *LLVM.DebugInfo.Subprogram, function: *LLVM.Value.Constant.Function) void; pub extern fn NativityLLVMDebugInfoBuilderFinalize(builder: *LLVM.DebugInfo.Builder) void; -pub extern fn NativityLLVMDebugInfoSubprogramGetFile(subprogram: *LLVM.DebugInfo.Subprogram) ?*LLVM.DebugInfo.File; -pub extern fn NativityLLVMDebugInfoSubprogramGetArgumentType(subprogram: *LLVM.DebugInfo.Subprogram, argument_index: usize) ?*LLVM.DebugInfo.Type; +pub extern fn NativityLLVMDebugInfoSubprogramGetFile(subprogram: *LLVM.DebugInfo.Subprogram) *LLVM.DebugInfo.File; +pub extern fn NativityLLVMDebugInfoSubprogramGetArgumentType(subprogram: *LLVM.DebugInfo.Subprogram, argument_index: usize) *LLVM.DebugInfo.Type; pub extern fn NativityLLVMDebugInfoScopeToSubprogram(scope: *LLVM.DebugInfo.Scope) ?*LLVM.DebugInfo.Subprogram; -pub extern fn NativityLLVMCreateBasicBlock(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, parent_function: ?*LLVM.Value.Constant.Function, insert_before: ?*LLVM.Value.BasicBlock) ?*LLVM.Value.BasicBlock; +pub extern fn NativityLLVMCreateBasicBlock(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, parent_function: ?*LLVM.Value.Constant.Function, insert_before: ?*LLVM.Value.BasicBlock) *LLVM.Value.BasicBlock; pub extern fn NativityLLVMBasicBlockRemoveFromParent(basic_block: *LLVM.Value.BasicBlock) void; pub extern fn NativityLLVMBuilderSetInsertPoint(builder: *LLVM.Builder, basic_block: *LLVM.Value.BasicBlock) void; -pub extern fn NativityLLVMBuilderGetInsertBlock(builder: *LLVM.Builder) ?*LLVM.Value.BasicBlock; +pub extern fn NativityLLVMBuilderGetInsertBlock(builder: *LLVM.Builder) *LLVM.Value.BasicBlock; pub extern fn NativityLLVMBuilderSetCurrentDebugLocation(builder: *LLVM.Builder, context: *LLVM.Context, line: c_uint, column: c_uint, scope: *LLVM.DebugInfo.Scope, function: *LLVM.Value.Constant.Function) void; pub extern fn NativityLLVMValueSetName(value: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) void; pub extern fn NativityLLVMValueGetType(value: *LLVM.Value) *LLVM.Type; pub extern fn NativityLLVMArgumentGetIndex(argument: *LLVM.Value.Argument) c_uint; pub extern fn NativityLLVMFunctionGetArguments(function: *LLVM.Value.Constant.Function, argument_ptr: [*]*LLVM.Value.Argument, argument_len: *usize) void; -pub extern fn NativityLLVMFunctionGetArgument(function: *LLVM.Value.Constant.Function, index: c_uint) ?*LLVM.Value.Argument; +pub extern fn NativityLLVMFunctionGetArgument(function: *LLVM.Value.Constant.Function, index: c_uint) *LLVM.Value.Argument; pub extern fn NativityLLVMFunctionGetType(function: *LLVM.Value.Constant.Function) *LLVM.Type.Function; pub extern fn NativityLLVMFunctionTypeGetReturnType(function_type: *LLVM.Type.Function) *LLVM.Type; pub extern fn NativityLLVMTypeIsVoid(type: *LLVM.Type) bool; -pub extern fn NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*LLVM.Value.Instruction.Alloca; -pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool, alignment: u32) ?*LLVM.Value.Instruction.Store; +pub extern fn NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize, alignment: u32) *LLVM.Value.Instruction.Alloca; +pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool, alignment: u32) *LLVM.Value.Instruction.Store; pub extern fn NativityLLVMBuilderCreateMemcpy(builder: *LLVM.Builder, destination: *LLVM.Value, destination_alignment: u32, source: *LLVM.Value, source_alignment: u32, size: u64, is_volatile: bool) *LLVM.Value.Instruction.Call; -pub extern fn NativityLLVMContextGetConstantInt(context: *LLVM.Context, bit_count: c_uint, value: u64, is_signed: bool) ?*LLVM.Value.Constant.Int; -pub extern fn NativityLLVMContextGetConstantString(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, null_terminate: bool) ?*LLVM.Value.Constant; -pub extern fn NativityLLVMGetConstantArray(array_type: *LLVM.Type.Array, value_ptr: [*]const *LLVM.Value.Constant, value_count: usize) ?*LLVM.Value.Constant; -pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) ?*LLVM.Value.Constant; +pub extern fn NativityLLVMContextGetConstantInt(context: *LLVM.Context, bit_count: c_uint, value: u64, is_signed: bool) *LLVM.Value.Constant.Int; +pub extern fn NativityLLVMContextGetConstantString(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, null_terminate: bool) *LLVM.Value.Constant; +pub extern fn NativityLLVMGetConstantArray(array_type: *LLVM.Type.Array, value_ptr: [*]const *LLVM.Value.Constant, value_count: usize) *LLVM.Value.Constant; +pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) *LLVM.Value.Constant; pub extern fn NativityLLVMConstantToInt(constant: *LLVM.Value.Constant) ?*LLVM.Value.Constant.Int; -pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*LLVM.Value.Instruction.Load; -pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) ?*LLVM.Value.Instruction.Ret; -pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; +pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) *LLVM.Value.Instruction.Load; +pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) *LLVM.Value.Instruction.Ret; +pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; pub extern fn NativityLLVMContextGetAttributeFromEnum(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, attribute_value: u64) *LLVM.Attribute; pub extern fn NativityLLVMContextGetAttributeFromString(context: *LLVM.Context, key_ptr: [*]const u8, key_len: usize, value_ptr: [*]const u8, value_len: usize) *LLVM.Attribute; pub extern fn NativityLLVMContextGetAttributeFromType(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, type: *LLVM.Type) *LLVM.Attribute; @@ -73,50 +74,51 @@ pub extern fn NativityLLVMContextGetAttributeSet(context: *LLVM.Context, attribu pub extern fn NativityLLVMFunctionSetAttributes(function: *LLVM.Value.Constant.Function, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void; pub extern fn NativityLLVMCallSetAttributes(call: *LLVM.Value.Instruction.Call, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void; // pub extern fn NativityLLVMFunctionAddAttributeKey(builder: *LLVM.Value.Constant.Function, attribute_key: LLVM.Attribute) void; -pub extern fn NativityLLVMGetVoidType(context: *LLVM.Context) ?*LLVM.Type; -pub extern fn NativityLLVMGetInlineAssembly(function_type: *LLVM.Type.Function, assembly_ptr: [*]const u8, assembly_len: usize, constraints_ptr: [*]const u8, constrains_len: usize, has_side_effects: bool, is_align_stack: bool, dialect: LLVM.Value.InlineAssembly.Dialect, can_throw: bool) ?*LLVM.Value.InlineAssembly; -pub extern fn NativityLLVMBuilderCreateCall(builder: *LLVM.Builder, function_type: *LLVM.Type.Function, callee: *LLVM.Value, argument_ptr: [*]const *LLVM.Value, argument_count: usize, name_ptr: [*]const u8, name_len: usize, fp_math_tag: ?*LLVM.Metadata.Node) ?*LLVM.Value.Instruction.Call; -pub extern fn NativityLLVMBuilderCreateUnreachable(builder: *LLVM.Builder) ?*LLVM.Value.Instruction.Unreachable; -pub extern fn NativityLLVMModuleAddGlobalVariable(module: *LLVM.Module, type: *LLVM.Type, is_constant: bool, linkage: LLVM.Linkage, initializer: ?*LLVM.Value.Constant, name_ptr: [*]const u8, name_len: usize, insert_before: ?*LLVM.Value.Constant.GlobalVariable, thread_local_mode: LLVM.ThreadLocalMode, address_space: c_uint, externally_initialized: bool) ?*LLVM.Value.Constant.GlobalVariable; +pub extern fn NativityLLVMGetVoidType(context: *LLVM.Context) *LLVM.Type; +pub extern fn NativityLLVMGetInlineAssembly(function_type: *LLVM.Type.Function, assembly_ptr: [*]const u8, assembly_len: usize, constraints_ptr: [*]const u8, constrains_len: usize, has_side_effects: bool, is_align_stack: bool, dialect: LLVM.Value.InlineAssembly.Dialect, can_throw: bool) *LLVM.Value.InlineAssembly; +pub extern fn NativityLLVMBuilderCreateCall(builder: *LLVM.Builder, function_type: *LLVM.Type.Function, callee: *LLVM.Value, argument_ptr: [*]const *LLVM.Value, argument_count: usize, name_ptr: [*]const u8, name_len: usize, fp_math_tag: ?*LLVM.Metadata.Node) *LLVM.Value.Instruction.Call; +pub extern fn NativityLLVMBuilderCreateUnreachable(builder: *LLVM.Builder) *LLVM.Value.Instruction.Unreachable; +pub extern fn NativityLLVMModuleAddGlobalVariable(module: *LLVM.Module, type: *LLVM.Type, is_constant: bool, linkage: LLVM.Linkage, initializer: ?*LLVM.Value.Constant, name_ptr: [*]const u8, name_len: usize, insert_before: ?*LLVM.Value.Constant.GlobalVariable, thread_local_mode: LLVM.ThreadLocalMode, address_space: c_uint, externally_initialized: bool) *LLVM.Value.Constant.GlobalVariable; -pub extern fn NativityLLVMBuilderCreateAdd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateSub(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateMultiply(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateShiftLeft(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value; +pub extern fn NativityLLVMBuilderCreateAdd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateSub(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateMultiply(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateShiftLeft(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) *LLVM.Value; -pub extern fn NativityLLVMBuilderCreateUDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateSDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateURem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateSRem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateLogicalShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateArithmeticShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value; +pub extern fn NativityLLVMBuilderCreateUDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateSDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateURem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateSRem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateLogicalShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateArithmeticShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) *LLVM.Value; -pub extern fn NativityLLVMBuilderCreateXor(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateAnd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateOr(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateGEP(builder: *LLVM.Builder, type: *LLVM.Type, pointer: *LLVM.Value, index_ptr: [*]const *LLVM.Value, index_count: usize, name_ptr: [*]const u8, name_len: usize, in_bounds: bool) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateStructGEP(builder: *LLVM.Builder, type: *LLVM.Type, pointer: *LLVM.Value, index: c_uint, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateBranch(builder: *LLVM.Builder, basic_block: *LLVM.Value.BasicBlock) ?*LLVM.Value.Instruction.Branch; -pub extern fn NativityLLVMBuilderCreateConditionalBranch(builder: *LLVM.Builder, condition: *LLVM.Value, true_block: *LLVM.Value.BasicBlock, false_block: *LLVM.Value.BasicBlock, branch_weights: ?*LLVM.Metadata.Node, unpredictable: ?*LLVM.Metadata.Node) ?*LLVM.Value.Instruction.Branch; +pub extern fn NativityLLVMBuilderCreateXor(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateAnd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateOr(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateGEP(builder: *LLVM.Builder, type: *LLVM.Type, pointer: *LLVM.Value, index_ptr: [*]const *LLVM.Value, index_count: usize, name_ptr: [*]const u8, name_len: usize, in_bounds: bool) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateStructGEP(builder: *LLVM.Builder, type: *LLVM.Type, pointer: *LLVM.Value, index: c_uint, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateBranch(builder: *LLVM.Builder, basic_block: *LLVM.Value.BasicBlock) *LLVM.Value.Instruction.Branch; +pub extern fn NativityLLVMBuilderCreateConditionalBranch(builder: *LLVM.Builder, condition: *LLVM.Value, true_block: *LLVM.Value.BasicBlock, false_block: *LLVM.Value.BasicBlock, branch_weights: ?*LLVM.Metadata.Node, unpredictable: ?*LLVM.Metadata.Node) *LLVM.Value.Instruction.Branch; pub extern fn NativityLLVMBuilderCreateSwitch(builder: *LLVM.Builder, condition: *LLVM.Value, default_block: ?*LLVM.Value.BasicBlock, case_ptr: [*]const *LLVM.Value.Constant.Int, case_block_ptr: [*]const *LLVM.Value.BasicBlock, case_count: c_uint, branch_weights: ?*LLVM.Metadata.Node, unpredictable: ?*LLVM.Metadata.Node) *LLVM.Value.Instruction.Switch; pub extern fn NativityLLVMVerifyFunction(function: *LLVM.Value.Constant.Function, message_ptr: *[*]const u8, message_len: *usize) bool; pub extern fn NativityLLVMVerifyModule(module: *LLVM.Module, message_ptr: *[*]const u8, message_len: *usize) bool; -pub extern fn NativityLLVMModuleToString(module: *LLVM.Module, message_len: *usize) [*]const u8; -pub extern fn NativityLLVMFunctionToString(function: *LLVM.Value.Constant.Function, message_len: *usize) [*]const u8; -pub extern fn NativityLLVMValueToString(value: *LLVM.Value, message_len: *usize) [*]const u8; +pub extern fn NativityLLVMModuleToString(module: *LLVM.Module, message_pointer: *[*]const u8, message_len: *usize) void; +pub extern fn NativityLLVMFunctionToString(function: *LLVM.Value.Constant.Function, message_pointer: *[*]const u8, message_len: *usize) void; +pub extern fn NativityLLVMValueToString(value: *LLVM.Value, message_pointer: *[*]const u8, message_len: *usize) void; pub extern fn NativityLLVMBuilderIsCurrentBlockTerminated(builder: *LLVM.Builder) bool; -pub extern fn NativityLLVMGetUndefined(type: *LLVM.Type) ?*LLVM.Value.Constant.Undefined; -pub extern fn NativityLLVMGetPoisonValue(type: *LLVM.Type) ?*LLVM.Value.Constant.Poison; +pub extern fn NativityLLVMGetUndefined(type: *LLVM.Type) *LLVM.Value.Constant.Undefined; +pub extern fn NativityLLVMGetPoisonValue(type: *LLVM.Type) *LLVM.Value.Constant.Poison; +pub extern fn NativityLLVMTypeGetContext(type: *LLVM.Type) *LLVM.Context; pub extern fn NativityLLVMFunctionSetCallingConvention(function: *LLVM.Value.Constant.Function, calling_convention: LLVM.Value.Constant.Function.CallingConvention) void; pub extern fn NativityLLVMFunctionGetCallingConvention(function: *LLVM.Value.Constant.Function) LLVM.Value.Constant.Function.CallingConvention; pub extern fn NativityLLVMFunctionSetSubprogram(function: *LLVM.Value.Constant.Function, subprogram: *LLVM.DebugInfo.Subprogram) void; -pub extern fn NativityLLVMFunctionGetSubprogram(function: *LLVM.Value.Constant.Function) ?*LLVM.DebugInfo.Subprogram; +pub extern fn NativityLLVMFunctionGetSubprogram(function: *LLVM.Value.Constant.Function) *LLVM.DebugInfo.Subprogram; pub extern fn NativityLLVMCallSetCallingConvention(instruction: *LLVM.Value.Instruction.Call, calling_convention: LLVM.Value.Constant.Function.CallingConvention) void; -pub extern fn NativityLLVMGetStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) ?*LLVM.Value.Constant; +pub extern fn NativityLLVMGetStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) *LLVM.Value.Constant; pub extern fn NativityLLVMValueToConstant(value: *LLVM.Value) ?*LLVM.Value.Constant; pub extern fn NativityLLVMValueToFunction(value: *LLVM.Value) ?*LLVM.Value.Constant.Function; @@ -129,29 +131,30 @@ pub extern fn NativityLLVMTypeToFunction(type: *LLVM.Type) ?*LLVM.Type.Function; pub extern fn NativityLLVMTypeToArray(type: *LLVM.Type) ?*LLVM.Type.Array; pub extern fn NativityLLVMTypeToPointer(Type: *LLVM.Type) ?*LLVM.Type.Pointer; -pub extern fn NativityLLVMArrayTypeGetElementType(array_type: *LLVM.Type.Array) ?*LLVM.Type; +pub extern fn NativityLLVMArrayTypeGetElementType(array_type: *LLVM.Type.Array) *LLVM.Type; pub extern fn NativityLLVMLookupIntrinsic(name_ptr: [*]const u8, name_len: usize) LLVM.Value.IntrinsicID; -pub extern fn NativityLLVMModuleGetIntrinsicDeclaration(module: *LLVM.Module, intrinsic_id: LLVM.Value.IntrinsicID, parameter_types_ptr: [*]const *LLVM.Type, parameter_type_count: usize) ?*LLVM.Value.Constant.Function; -pub extern fn NativityLLVMContextGetIntrinsicType(context: *LLVM.Context, intrinsic_id: LLVM.Value.IntrinsicID, parameter_type_ptr: [*]const *LLVM.Type, parameter_type_count: usize) ?*LLVM.Type.Function; -pub extern fn NativityLLVMBuilderCreateExtractValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateInsertValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, value: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateGlobalString(builder: *LLVM.Builder, string_ptr: [*]const u8, string_len: usize, name_ptr: [*]const u8, name_len: usize, address_space: c_uint, module: *LLVM.Module) ?*LLVM.Value.Constant.GlobalVariable; -pub extern fn NativityLLVMBuilderCreateGlobalStringPointer(builder: *LLVM.Builder, string_ptr: [*]const u8, string_len: usize, name_ptr: [*]const u8, name_len: usize, address_space: c_uint, module: *LLVM.Module) ?*LLVM.Value.Constant; +pub extern fn NativityLLVMModuleGetIntrinsicDeclaration(module: *LLVM.Module, intrinsic_id: LLVM.Value.IntrinsicID, parameter_types_ptr: [*]const *LLVM.Type, parameter_type_count: usize) *LLVM.Value.Constant.Function; +pub extern fn NativityLLVMContextGetIntrinsicType(context: *LLVM.Context, intrinsic_id: LLVM.Value.IntrinsicID, parameter_type_ptr: [*]const *LLVM.Type, parameter_type_count: usize) *LLVM.Type.Function; +pub extern fn NativityLLVMBuilderCreateExtractValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateInsertValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, value: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) *LLVM.Value; +pub extern fn NativityLLVMBuilderCreateGlobalString(builder: *LLVM.Builder, string_ptr: [*]const u8, string_len: usize, name_ptr: [*]const u8, name_len: usize, address_space: c_uint, module: *LLVM.Module) *LLVM.Value.Constant.GlobalVariable; +pub extern fn NativityLLVMBuilderCreateGlobalStringPointer(builder: *LLVM.Builder, string_ptr: [*]const u8, string_len: usize, name_ptr: [*]const u8, name_len: usize, address_space: c_uint, module: *LLVM.Module) *LLVM.Value.Constant; pub extern fn NativityLLVMCompareTypes(a: *LLVM.Type, b: *LLVM.Type) bool; -pub extern fn NativityLLVMBuilderCreatePhi(builder: *LLVM.Builder, type: *LLVM.Type, reserved_value_count: c_uint, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Instruction.PhiNode; +pub extern fn NativityLLVMBuilderCreatePhi(builder: *LLVM.Builder, type: *LLVM.Type, reserved_value_count: c_uint, name_ptr: [*]const u8, name_len: usize) *LLVM.Value.Instruction.PhiNode; pub extern fn NativityLLVMPhiAddIncoming(phi: *LLVM.Value.Instruction.PhiNode, value: *LLVM.Value, basic_block: *LLVM.Value.BasicBlock) void; 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 NativityLLVMInitializeCodeGeneration() void; +pub extern fn NativityLLVMLinkModules(destination: *LLVM.Module, source: *LLVM.Module, flags: LLVM.LinkFlags) bool; + 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.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 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 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 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 NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void; pub extern fn LLVMInitializeAArch64TargetInfo() void; diff --git a/bootstrap/compiler.zig b/bootstrap/compiler.zig new file mode 100644 index 0000000..2774268 --- /dev/null +++ b/bootstrap/compiler.zig @@ -0,0 +1,3074 @@ +const std = @import("std"); +const library = @import("library.zig"); +const assert = library.assert; +const Arena = library.Arena; +const PinnedArray = library.PinnedArray; +const PinnedHashMap = library.PinnedHashMap; +const hash_bytes = library.my_hash; +const byte_equal = library.byte_equal; + +fn exit(exit_code: u8) noreturn { + @setCold(true); + if (@import("builtin").mode == .Debug) { + if (exit_code != 0) @trap(); + } + std.posix.exit(exit_code); +} + +fn is_space(ch: u8) bool { + const is_whitespace = ch == ' '; + const is_tab = ch == '\t'; + const is_line_feed = ch == '\n'; + const is_carry_return = ch == '\r'; + const result = (is_whitespace or is_tab) or (is_line_feed or is_carry_return); + return result; +} + +fn write(string: []const u8) void { + std.io.getStdOut().writeAll(string) catch unreachable; +} + +fn exit_with_error(string: []const u8) noreturn { + @setCold(true); + write("error: "); + write(string); + write("\n"); + exit(1); +} + +fn is_lower(ch: u8) bool { + return ch >= 'a' and ch <= 'z'; +} + +fn is_upper(ch: u8) bool { + return ch >= 'A' and ch <= 'Z'; +} + +fn is_decimal_digit(ch: u8) bool { + return ch >= '0' and ch <= '9'; +} + +fn is_alphabetic(ch: u8) bool { + const lower = is_lower(ch); + const upper = is_upper(ch); + return lower or upper; +} + +fn is_identifier_char_start(ch: u8) bool { + const is_alpha = is_alphabetic(ch); + const is_underscore = ch == '_'; + return is_alpha or is_underscore; +} + +fn is_identifier_char(ch: u8) bool { + const is_identifier_start_ch = is_identifier_char_start(ch); + const is_digit = is_decimal_digit(ch); + return is_identifier_start_ch or is_digit; +} + +const GlobalSymbol = struct{ + attributes: Attributes = .{}, + name: u32, + const Attributes = struct{ + @"export": bool = false, + @"extern": bool = false, + }; + const Attribute = enum{ + @"export", + @"extern", + + const Mask = std.EnumSet(Attribute); + }; +}; + +const Parser = struct{ + i: u64 = 0, + current_line: u32 = 0, + line_offset: u32 = 0, + + fn skip_space(parser: *Parser, file: []const u8) void { + const original_i = parser.i; + + if (!is_space(file[original_i])) return; + + while (parser.i < file.len) : (parser.i += 1) { + const ch = file[parser.i]; + const new_line = ch == '\n'; + parser.current_line += @intFromBool(new_line); + + if (new_line) { + parser.line_offset = @intCast(parser.i); + } + + if (!is_space(ch)) { + return; + } + } + } + + fn parse_raw_identifier(parser: *Parser, file: []const u8) []const u8 { + const identifier_start = parser.i; + const is_string_literal_identifier = file[identifier_start] == '"'; + parser.i += @intFromBool(is_string_literal_identifier); + const start_ch = file[parser.i]; + const is_valid_identifier_start = is_identifier_char_start(start_ch); + parser.i += @intFromBool(is_valid_identifier_start); + + if (is_valid_identifier_start) { + while (parser.i < file.len) { + const ch = file[parser.i]; + const is_ident = is_identifier_char(ch); + parser.i += @intFromBool(is_ident); + + if (!is_ident) { + if (is_string_literal_identifier) { + if (file[parser.i] != '"') { + exit(1); + } + } + + const identifier = file[identifier_start..parser.i]; + return identifier; + } + } else { + exit(1); + } + } else { + exit(1); + } + } + + fn parse_identifier(parser: *Parser, thread: *Thread, file: []const u8) u32 { + const identifier = parser.parse_raw_identifier(file); + if (identifier[0] != '"') { + const keyword = parse_keyword(identifier); + if (keyword != ~(@as(u32, 0))) { + exit(1); + } + } + const hash = intern_identifier(&thread.identifiers, identifier); + return hash; + } + + fn parse_non_escaped_string_literal(parser: *Parser, src: []const u8) []const u8 { + const start = parser.i; + const is_double_quote = src[start] == '"'; + parser.i += @intFromBool(is_double_quote); + + if (!is_double_quote) { + exit(1); + } + + while (src[parser.i] != '"') : (parser.i += 1) { + if (src[parser.i] == '\\') exit(1); + } + + parser.i += 1; + + const end = parser.i; + + return src[start..end]; + } + + fn parse_non_escaped_string_literal_content(parser: *Parser, src: []const u8) []const u8 { + const string_literal = parser.parse_non_escaped_string_literal(src); + return string_literal[1..][0..string_literal.len - 2]; + } + + fn expect_character(parser: *Parser, file: []const u8, expected: u8) void { + const index = parser.i; + if (index < file.len) { + const ch = file[index]; + const matches = ch == expected; + parser.i += @intFromBool(matches); + if (!matches) { + exit(1); + } + } else { + exit(1); + } + } + + fn parse_type_expression(parser: *Parser, thread: *Thread, src: []const u8) *Type { + const starting_ch = src[parser.i]; + const is_start_u = starting_ch == 'u'; + const is_start_s = starting_ch == 's'; + const float_start = starting_ch == 'f'; + const integer_start = is_start_s or is_start_u; + const is_number_type_start = integer_start or float_start; + + if (is_number_type_start) { + const expected_digit_start = parser.i + 1; + var i = expected_digit_start; + var decimal_digit_count: u32 = 0; + + const top = i + 5; + + while (i < top) : (i += 1) { + const ch = src[i]; + const is_digit = is_decimal_digit(ch); + decimal_digit_count += @intFromBool(is_digit); + if (!is_digit) { + const is_alpha = is_alphabetic(ch); + if (is_alpha) decimal_digit_count = 0; + break; + } + } + + if (decimal_digit_count != 0) { + parser.i += 1; + + if (integer_start) { + const signedness: Type.Integer.Signedness = @enumFromInt(@intFromBool(is_start_s)); + const bit_count: u32 = switch (decimal_digit_count) { + 0 => unreachable, + 1 => src[parser.i] - '0', + 2 => @as(u32, src[parser.i] - '0') * 10 + (src[parser.i + 1] - '0'), + else => exit(1), + }; + parser.i += decimal_digit_count; + + const index = bit_count + (@intFromEnum(signedness) * @as(u32, 64) + @intFromEnum(signedness)); + const t = &thread.types.slice()[index]; + return t; + } else if (float_start) { + exit(1); + } else { + unreachable; + } + } else { + exit(1); + } + } else { + exit(1); + } + } + + fn parse_typed_expression(parser: *Parser, analyzer: *Analyzer, thread: *Thread, file: *File, ty: *Type) *Value { + const src = file.source_code; + assert(ty.sema.id != .unresolved); + const starting_ch = src[parser.i]; + const is_digit_start = is_decimal_digit(starting_ch); + const is_alpha_start = is_alphabetic(starting_ch); + + if (is_digit_start) { + switch (ty.sema.id) { + .integer => { + if (starting_ch == '0') { + const follow_up_character = src[parser.i + 1]; + const is_hex_start = follow_up_character == 'x'; + const is_octal_start = follow_up_character == 'o'; + const is_bin_start = follow_up_character == 'b'; + const is_prefixed_start = is_hex_start or is_octal_start or is_bin_start; + const follow_up_alpha = is_alphabetic(follow_up_character); + const follow_up_digit = is_decimal_digit(follow_up_character); + const is_valid_after_zero = is_space(follow_up_character) or (!follow_up_digit and !follow_up_alpha); + // + if (is_prefixed_start) { + exit(1); + } else if (is_valid_after_zero) { + parser.i += 1; + const constant_int_index = thread.constant_ints.append_index(.{ + .value = 0, + .type = ty, + }); + + const value = thread.values.append(.{ + .sema = .{ + .id = .constant_int, + .index = @intCast(constant_int_index), + .thread = @intCast(thread.get_index()), + .resolved = true, + }, + }); + return value; + } else { + exit(1); + } + } + exit(0); + }, + else => unreachable, + } + } else if (is_alpha_start) { + const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index)); + + var resolved = true; + const identifier = parser.parse_identifier(thread, src); + const lazy_expression = thread.lazy_expressions.add_one(); + + if (file_scope.declarations.get_pointer(identifier)) |declaration| { + switch (declaration.id) { + .unresolved_import => { + resolved = false; + lazy_expression.* = LazyExpression.init(declaration); + + while (true) { + switch (src[parser.i]) { + '.' => { + parser.i += 1; + const right = parser.parse_identifier(thread, src); + lazy_expression.add(right); + }, + '(' => break, + else => @panic((src.ptr + parser.i)[0..1]), + } + } + + const expression = thread.values.append(.{ + .sema = .{ + .id = .lazy_expression, + .index = thread.lazy_expressions.get_index(lazy_expression), + .thread = thread.get_index(), + .resolved = false, + }, + }); + + switch (src[parser.i]) { + '(' => { + parser.i += 1; + // TODO: arguments + parser.expect_character(src, ')'); + + const call = thread.calls.append_index(.{ + .value = expression, + }); + const call_i = thread.instructions.append(.{ + .id = .call, + .index = @intCast(call), + }); + _ = analyzer.current_basic_block.instructions.append(call_i); + + const call_value = thread.values.append(.{ + .sema = .{ + .id = .instruction, + .index = thread.instructions.get_index(call_i), + .thread = thread.get_index(), + .resolved = false, + }, + }); + + _ = thread.pending_file_values.get(@enumFromInt(declaration.index)).append(call_value); + return call_value; + }, + else => @panic((src.ptr + parser.i)[0..1]), + } + }, + else => |t| @panic(@tagName(t)), + } + } else { + exit(1); + } + } else { + exit(1); + } + } +}; + +const LazyExpression = union(enum) { + dynamic: struct{ + names: PinnedArray(u32) = .{}, + outsider: *GlobalSymbolReference, + }, + static: struct { + names: [4]u32 = .{0} ** 4, + outsider: *GlobalSymbolReference, + }, + + fn init(gsr: *GlobalSymbolReference) LazyExpression { + return .{ + .static = .{ + .outsider = gsr, + }, + }; + } + + fn length(lazy_expression: *LazyExpression) u32 { + return switch (lazy_expression.*) { + .dynamic => |d| d.names.length, + .static => |*s| for (s.names, 0..) |n, i| { + if (n == 0) break @intCast(i); + } else s.names.len, + }; + } + + fn names(lazy_expression: *LazyExpression) []const u32 { + return switch (lazy_expression.*) { + .dynamic => |*d| d.names.slice(), + .static => |*s| s.names[0.. for (s.names, 0..) |n, i| { + if (n == 0) break @intCast(i); + } else s.names.len], + }; + } + + fn add(lazy_expression: *LazyExpression, name: u32) void { + const index = lazy_expression.length(); + if (index < 4) { + lazy_expression.static.names[index] = name; + } else { + unreachable; + } + } +}; + +fn Descriptor(comptime Id: type, comptime Integer: type) type { + return packed struct(Integer) { + index: @Type(.{ + .Int = .{ + .signedness = .unsigned, + .bits = @typeInfo(Integer).Int.bits - @typeInfo(@typeInfo(Id).Enum.tag_type).Int.bits, + }, + }), + id: Id, + + pub const Index = PinnedArray(@This()).Index; + }; +} + +const Expression = struct{ + type: *Type, + value: *Value, +}; + +const Value = struct { + llvm: ?*LLVM.Value = null, + sema: packed struct(u64) { + index: u32, + thread: u16, + resolved: bool, + reserved: u7 = 0, + id: Id, + }, + const Id = enum(u8){ + constant_int, + lazy_expression, + instruction, + global_symbol, + }; +}; + +const Type = struct { + llvm: ?*LLVM.Type = null, + sema: packed struct(u32) { + index: u24, + id: Id, + }, + + const Id = enum(u8){ + unresolved, + void, + integer, + }; + + const Integer = packed struct(u32) { + bit_count: u16, + signedness: Signedness, + reserved: u7 = 0, + id: Id = .integer, + + const Signedness = enum(u1){ + unsigned, + signed, + }; + }; +}; + + +fn integer_bit_count(t: *Type) u16 { + const integer: Type.Integer = @bitCast(t.sema); + return integer.bit_count; +} + +fn integer_signedness(t: *Type) Type.Integer.Signedness { + const integer: Type.Integer = @bitCast(t.sema); + return integer.signedness; +} + +const IntegerType = struct{ +}; + +const Keyword = enum{ + @"for", +}; + +fn parse_keyword(identifier: []const u8) u32 { + inline for (@typeInfo(Keyword).Enum.fields) |keyword| { + if (byte_equal(identifier, keyword.name)) { + return keyword.value; + } + } else { + return ~@as(u32, 0); + } +} + +const Scope = Descriptor(enum(u3) { + file, + function, + local, +}, u32); +const Range = struct{ + start: u32, + end: u32, +}; + +const FileScope = struct{ + declarations: PinnedHashMap(u32, GlobalSymbolReference) = .{}, +}; + +const GlobalSymbolReference = Descriptor(enum(u3) { + function_definition, + function_declaration, + file, + unresolved_import, +}, u32); + +const BasicBlock = struct{ + instructions: PinnedArray(*Instruction) = .{}, + predecessors: PinnedArray(u32) = .{}, + is_terminated: bool = false, + + const Index = PinnedArray(BasicBlock).Index; +}; + +const Function = struct{ + declaration: Function.Declaration, + entry_block: BasicBlock.Index, + + const Attributes = struct{ + calling_convention: CallingConvention = .custom, + }; + + const Attribute = enum{ + cc, + + pub const Mask = std.EnumSet(Function.Attribute); + }; + const Declaration = struct { + attributes: Attributes = .{}, + global: GlobalSymbol, + return_type: *Type, + argument_types: []const Type = &.{}, + file: u32, + llvm: ?*LLVM.Value.Constant.Function = null, + }; +}; + + +const Instruction = struct{ + index: u24, + id: Id, + llvm: ?*LLVM.Value = null, + + const Id = enum{ + call, + ret, + ret_void, + }; +}; + +const ConstantInt = struct{ + value: u64, + type: *Type, +}; + + +const Call = struct{ + value: *Value, + const Index = PinnedArray(Call).Index; +}; + +const Return = struct{ + value: *Value, + const Index = PinnedArray(Call).Index; +}; + +const Thread = struct{ + arena: *Arena = undefined, + functions: PinnedArray(Function) = .{}, + external_functions: PinnedArray(Function.Declaration) = .{}, + identifiers: PinnedHashMap(u32, []const u8) = .{}, + instructions: PinnedArray(Instruction) = .{}, + constant_ints: PinnedArray(ConstantInt) = .{}, + basic_blocks: PinnedArray(BasicBlock) = .{}, + task_system: TaskSystem = .{}, + analyzed_file_count: u32 = 0, + debug_info_file_map: PinnedHashMap(u32, LLVMFile) = .{}, + local_files: PinnedHashMap(u32, u32) = .{}, + pending_files: PinnedArray(u32) = .{}, + pending_file_values: PinnedArray(PinnedArray(*Value)) = .{}, + file_scopes: PinnedArray(FileScope) = .{}, + expressions: PinnedArray(Expression) = .{}, + calls: PinnedArray(Call) = .{}, + returns: PinnedArray(Return) = .{}, + types: PinnedArray(Type) = .{}, + values: PinnedArray(Value) = .{}, + lazy_expressions: PinnedArray(LazyExpression) = .{}, + llvm: struct { + context: *LLVM.Context, + module: *LLVM.Module, + builder: *LLVM.Builder, + attributes: LLVM.Attributes, + } = undefined, + + + fn add_thread_work(thread: *Thread, job: Job) void { + thread.task_system.job.queue_job(job); + } + + fn add_control_work(thread: *Thread, job: Job) void { + thread.task_system.ask.queue_job(job); + } + + pub fn get_index(thread: *Thread) u16 { + const index = @divExact(@intFromPtr(thread) - @intFromPtr(threads.ptr), @sizeOf(Thread)); + return @intCast(index); + } +}; + +const instrument = true; + +const LLVMFile = struct { + file: *LLVM.DebugInfo.File, + compile_unit: *LLVM.DebugInfo.CompileUnit, + builder: *LLVM.DebugInfo.Builder, +}; + +const Job = packed struct(u64) { + offset: u32 = 0, + count: u24 = 0, + id: Id, + + const Id = enum(u8){ + analyze_file, + llvm_setup, + notify_file_resolved, + resolve_thread_module, + llvm_codegen_thread_module, + }; +}; + +const TaskSystem = struct{ + job: JobQueue = .{}, + ask: JobQueue = .{}, +}; + +const JobQueue = struct{ + entries: [64]Job = [1]Job{@bitCast(@as(u64, 0))} ** 64, + to_do: u64 = 0, + completed: u64 = 0, + + fn queue_job(job_queue: *JobQueue, job: Job) void { + const index = job_queue.to_do; + job_queue.entries[index] = job; + job_queue.to_do += 1; + } +}; + +var threads: []Thread = undefined; + +const Instance = struct{ + files: PinnedArray(File) = .{}, + file_paths: PinnedArray(u32) = .{}, + arena: *Arena = undefined, +}; + +const File = struct{ + scope: Scope, + source_code: []const u8, + path: []const u8, + functions: Range = .{ + .start = 0, + .end = 0, + }, + state: State = .queued, + thread: u32 = 0, + interested_threads: PinnedArray(u32) = .{}, + + pub fn get_directory_path(file: *const File) []const u8 { + return std.fs.path.dirname(file.path) orelse unreachable; + } + + const State = enum{ + queued, + analyzing, + }; + + const Index = PinnedArray(File).Index; +}; + +var instance = Instance{}; +const do_codegen = true; +const codegen_backend = CodegenBackend.llvm; + +const CodegenBackend = enum{ + llvm, +}; + +fn add_file(file_absolute_path: []const u8, interested_threads: []const u32) File.Index { + const hash = hash_bytes(file_absolute_path); + const new_file = instance.files.add_one(); + _ = instance.file_paths.append(hash); + const new_file_index = instance.files.get_typed_index(new_file); + new_file.* = .{ + .scope = @bitCast(@as(u32, 0)), + .source_code = &.{}, + .path = file_absolute_path, + }; + + new_file.interested_threads.append_slice(interested_threads); + + return new_file_index; +} + +pub fn make() void { + instance.arena = library.Arena.init(4 * 1024 * 1024) catch unreachable; + // var modules: [2]*LLVM.Module = undefined; + // { + // const context = LLVM.Context.create(); + // const module_name: []const u8 = "thread"; + // const module = LLVM.Module.create(module_name.ptr, module_name.len, context); + // const builder = LLVM.Builder.create(context); + // // const attributes = LLVM.Attributes{ + // // .naked = context.getAttributeFromEnum(.Naked, 0), + // // .noreturn = context.getAttributeFromEnum(.NoReturn, 0), + // // .nounwind = context.getAttributeFromEnum(.NoUnwind, 0), + // // .inreg = context.getAttributeFromEnum(.InReg, 0), + // // .@"noalias" = context.getAttributeFromEnum(.NoAlias, 0), + // // }; + // const int32 = context.getIntegerType(32); + // const function_type = LLVM.getFunctionType(int32.toType(), undefined, 0, false); + // const function = module.createFunction(function_type, .internal, 0, "foo", "foo".len); + // const entry_basic_block = context.createBasicBlock("", "".len, function, null); + // builder.setInsertPoint(entry_basic_block); + // + // const call_function = module.createFunction(function_type, .@"extern", 0, "fa", "fa".len); + // + // const call = builder.createCall(function_type, call_function.toValue(), undefined, 0, "", "".len, null); + // _ = builder.createRet(call.toValue()); + // var message: []const u8 = undefined; + // //_ = message; // autofix + // const v = module.verify(&message.ptr, &message.len); + // if (!v) exit_with_error(message); + // modules[0] = module; + // } + // + // { + // const context = LLVM.Context.create(); + // const module_name: []const u8 = "thread"; + // const module = LLVM.Module.create(module_name.ptr, module_name.len, context); + // const builder = LLVM.Builder.create(context); + // // const attributes = LLVM.Attributes{ + // // .naked = context.getAttributeFromEnum(.Naked, 0), + // // .noreturn = context.getAttributeFromEnum(.NoReturn, 0), + // // .nounwind = context.getAttributeFromEnum(.NoUnwind, 0), + // // .inreg = context.getAttributeFromEnum(.InReg, 0), + // // .@"noalias" = context.getAttributeFromEnum(.NoAlias, 0), + // // }; + // const int32 = context.getIntegerType(32); + // const function_type = LLVM.getFunctionType(int32.toType(), undefined, 0, false); + // const function = module.createFunction(function_type, .@"internal", 0, "fa", "fa".len); + // const entry_basic_block = context.createBasicBlock("", "".len, function, null); + // builder.setInsertPoint(entry_basic_block); + // + // const constant_int = context.getConstantInt(32, 5, false); + // _ = builder.createRet(constant_int.toValue()); + // var message: []const u8 = undefined; + // const v = module.verify(&message.ptr, &message.len); + // if (!v) exit_with_error(message); + // modules[1] = module; + // } + // + // const result = LLVMLinkModules2(modules[0], modules[1]); + // var foo: []const u8 = undefined; + // modules[0].toString(&foo.ptr, &foo.len); + // std.debug.print("Result: {}\n{s}\n", .{result, foo}); + + const thread_count = std.Thread.getCpuCount() catch unreachable; + cpu_count = @intCast(thread_count); + threads = instance.arena.new_array(Thread, cpu_count - 1) catch unreachable; + for (threads) |*thread| { + thread.* = .{}; + } + cpu_count -= 2; + _ = std.Thread.spawn(.{}, thread_callback, .{cpu_count}) catch unreachable; + + // Initialize LLVM in all threads + if (do_codegen) { + const llvm_job = Job{ + .offset = 0, + .count = 0, + .id = .llvm_setup, + }; + for (threads) |*thread| { + thread.add_thread_work(llvm_job); + } + } + + const first_file_relative_path = "retest/standalone/first/main.nat"; + const first_file_absolute_path = library.realpath(instance.arena, std.fs.cwd(), first_file_relative_path) catch unreachable; + const new_file_index = add_file(first_file_absolute_path, &.{}); + var last_assigned_thread_index: u32 = 0; + threads[last_assigned_thread_index].add_thread_work(Job{ + .offset = @intFromEnum(new_file_index), + .id = .analyze_file, + }); + + while (true) { + var worker_pending_tasks: u64 = 0; + var control_pending_tasks: u64 = 0; + for (threads) |*thread| { + worker_pending_tasks += thread.task_system.job.to_do - thread.task_system.job.completed; + control_pending_tasks += thread.task_system.ask.to_do - thread.task_system.ask.completed; + } + + const pending_tasks = worker_pending_tasks + control_pending_tasks; + if (pending_tasks == 0) { + break; + } + + if (control_pending_tasks > 0) { + for (threads, 0..) |*thread, i| { + const control_pending = thread.task_system.ask.to_do - thread.task_system.ask.completed; + if (control_pending != 0) { + const jobs_to_do = thread.task_system.ask.entries[thread.task_system.ask.completed .. thread.task_system.ask.to_do]; + + for (jobs_to_do) |job| { + switch (job.id) { + .analyze_file => { + last_assigned_thread_index += 1; + const analyze_file_path_hash = job.offset; + for (instance.file_paths.slice()) |file_path_hash| { + if (analyze_file_path_hash == file_path_hash) { + exit(1); + } + } else { + last_assigned_thread_index += 1; + const thread_index = last_assigned_thread_index % threads.len; + const file_absolute_path = thread.identifiers.get(analyze_file_path_hash).?; + const interested_thread_index: u32 = @intCast(i); + const file_index = add_file(file_absolute_path, &.{interested_thread_index}); + const assigned_thread = &threads[thread_index]; + assigned_thread.add_thread_work(Job{ + .offset = @intFromEnum(file_index), + .id = .analyze_file, + }); + } + }, + .notify_file_resolved => { + const file_index = job.offset; + const thread_index = job.count; + const destination_thread = &threads[thread_index]; + const file = instance.files.get(@enumFromInt(file_index)); + const file_path_hash = hash_bytes(file.path); + destination_thread.add_thread_work(.{ + .id = .notify_file_resolved, + .count = @intCast(file_index), + .offset = file_path_hash, + }); + }, + else => |t| @panic(@tagName(t)), + } + } + + thread.task_system.ask.completed += jobs_to_do.len; + } + } + } + } + + { + // finish thread semantic analysis + for (threads) |*thread| { + thread.add_thread_work(Job{ + .id = .resolve_thread_module, + }); + } + } + + // TODO: Prune + if (do_codegen) { + for (threads) |*thread| { + thread.add_thread_work(Job{ + .id = switch (codegen_backend) { + .llvm => .llvm_codegen_thread_module, + }, + }); + } + + while (true) { + var to_do: u64 = 0; + for (threads) |*thread| { + const jobs_to_do = thread.task_system.job.to_do - thread.task_system.job.completed; + const asks_to_do = thread.task_system.ask.to_do - thread.task_system.ask.completed; + assert(asks_to_do == 0); + + to_do += jobs_to_do; + } + + if (to_do == 0) { + break; + } + } + + var modules_present = PinnedArray(usize){}; + for (threads, 0..) |*thread, i| { + if (thread.functions.length > 0) { + _ = modules_present.append(i); + } + } + + switch (modules_present.length) { + 0 => unreachable, + 1 => unreachable, + 2 => { + const first = modules_present.slice()[0]; + const second = modules_present.slice()[1]; + const destination = threads[first].llvm.module; + { + var message: []const u8 = undefined; + destination.toString(&message.ptr, &message.len); + std.debug.print("{s}\n", .{message}); + } + const source = threads[second].llvm.module; + { + var message: []const u8 = undefined; + source.toString(&message.ptr, &message.len); + std.debug.print("{s}\n", .{message}); + } + + if (!destination.link(source, .{ + .override_from_source = true, + .link_only_needed = false, + })) { + exit(1); + } + + var message: []const u8 = undefined; + destination.toString(&message.ptr, &message.len); + std.debug.print("============\n===========\n{s}\n", .{message}); + }, + else => unreachable, + } + } + + // while (true) {} +} + +fn intern_identifier(pool: *PinnedHashMap(u32, []const u8), identifier: []const u8) u32 { + const start_index = @intFromBool(identifier[0] == '"'); + const end_index = identifier.len - start_index; + const hash = hash_bytes(identifier[start_index..end_index]); + pool.put(hash, identifier); + + return hash; +} + +// fn resolve_call(thread: *Thread, file_index: u32, expression: *Expression) void { +// assert(expression.kind == .unresolved and expression.kind.unresolved == .call_expression); +// const unresolved_call_expression = expression.kind.unresolved.call_expression; +// resolve_expression(thread, file_index, unresolved_call_expression.callee); +// const function_expression = unresolved_call_expression.callee; +// switch (function_expression.kind) { +// .resolved => |resolved| switch (resolved) { +// .declaration => |declaration| switch (declaration.id) { +// .function_definition => |fn_def| { +// _ = fn_def; // autofix +// _ = expression.instruction; +// const basic_block = thread.basic_blocks.get(expression.basic_block); +// const call = thread.calls.append_index(.{}); +// const instruction = thread.instructions.append(.{ +// .id = .call, +// .index = @intCast(@intFromEnum(call)), +// }); +// _ = basic_block.instructions.append(instruction); +// expression.kind = .{ +// .resolved = .{ +// .instruction = instruction, +// }, +// }; +// }, +// else => |t| @panic(@tagName(t)), +// }, +// else => |t| @panic(@tagName(t)), +// }, +// else => |t| @panic(@tagName(t)), +// } +// } + +fn resolve_value(thread: *Thread, file_index: u32, value: *Value) void { + _ = thread; // autofix + _ = file_index; // autofix + _ = value; // autofix + unreachable; + // switch (expression.kind) { + // .unresolved => |unresolved_expression| switch (unresolved_expression) { + // .import => |declaration| { + // declaration.* = .{ + // .id = .file, + // .index = @intCast(file_index), + // }; + // + // expression.kind = .{ + // .resolved = .{ + // .import = declaration, + // }, + // }; + // }, + // .call_expression => resolve_call(thread, file_index, expression), + // .field_expression => |field_expression| { + // resolve_expression(thread, file_index, field_expression.left); + // + // switch (field_expression.left.kind) { + // .resolved => |resolved_expression| switch (resolved_expression) { + // .import => |declaration| { + // assert(declaration.id == .file); + // const resolved_file_index = declaration.index; + // const file = &instance.files.pointer[resolved_file_index]; + // + // const file_scope = &threads[file.thread].file_scopes.pointer[file.scope.index]; + // if (file_scope.declarations.get_pointer(field_expression.right)) |symbol| { + // expression.kind = .{ + // .resolved = .{ + // .declaration = symbol, + // }, + // }; + // } else { + // exit(1); + // } + // }, + // else => |t| @panic(@tagName(t)), + // }, + // else => |t| @panic(@tagName(t)), + // } + // }, + // }, + // .resolved => {}, + // } +} + +fn get_integer_type(thread: *Thread) void { + _ = thread; // autofix +} + +const CallingConvention = enum{ + c, + custom, +}; + +const Analyzer = struct{ + current_basic_block: *BasicBlock = undefined, + current_function: *Function = undefined, +}; + +const bracket_open = 0x7b; +const bracket_close = 0x7d; + +var cpu_count: u32 = 0; + +const address_space = 0; + +fn thread_callback(thread_index: u32) void { + var created_thread_count: u32 = 0; + while (true) { + const local_cpu_count = cpu_count; + if (local_cpu_count == 0) { + break; + } + + if (@cmpxchgWeak(u32, &cpu_count, local_cpu_count, local_cpu_count - 1, .seq_cst, .seq_cst) == null) { + created_thread_count += 1; + const t = std.Thread.spawn(.{}, thread_callback, .{local_cpu_count - 1}) catch unreachable; + _ = t; // autofix + } + } + + const thread = &threads[thread_index]; + + thread.arena = Arena.init(4 * 1024 * 1024) catch unreachable; + + while (true) { + const to_do = thread.task_system.job.to_do; + const completed = thread.task_system.job.completed; + + if (completed < to_do) { + const jobs = thread.task_system.job.entries[completed..to_do]; + for (jobs) |job| { + switch (job.id) { + .llvm_setup => { + const context = LLVM.Context.create(); + const module_name: []const u8 = "thread"; + const module = LLVM.Module.create(module_name.ptr, module_name.len, context); + const builder = LLVM.Builder.create(context); + const attributes = LLVM.Attributes{ + .naked = context.getAttributeFromEnum(.Naked, 0), + .noreturn = context.getAttributeFromEnum(.NoReturn, 0), + .nounwind = context.getAttributeFromEnum(.NoUnwind, 0), + .inreg = context.getAttributeFromEnum(.InReg, 0), + .@"noalias" = context.getAttributeFromEnum(.NoAlias, 0), + }; + thread.llvm = .{ + .context = context, + .module = module, + .builder = builder, + .attributes = attributes, + }; + + for ([_]Type.Integer.Signedness{.unsigned, .signed}) |signedness| { + for (0..64+1) |bit_count| { + const integer_type = Type.Integer{ + .bit_count = @intCast(bit_count), + .signedness = signedness, + }; + _ = thread.types.append(.{ + .sema = @bitCast(integer_type), + }); + } + } + }, + .analyze_file => { + const file_index = job.offset; + const file = &instance.files.slice()[file_index]; + file.scope = .{ + .id = .file, + .index = @intCast(thread.file_scopes.append_index(.{})), + }; + file.state = .analyzing; + file.source_code = library.read_file(thread.arena, std.fs.cwd(), file.path); + file.thread = thread_index; + analyze_file(thread, file_index); + + // if (do_codegen and codegen_backend == .llvm) { + // } + + thread.analyzed_file_count += 1; + + for (file.interested_threads.slice()) |ti| { + thread.add_control_work(.{ + .id = .notify_file_resolved, + .offset = file_index, + .count = @intCast(ti), + }); + } + }, + .notify_file_resolved => { + const file_path_hash = job.offset; + const file_index = job.count; + const file = &instance.files.pointer[file_index]; + const file_scope = threads[file.thread].file_scopes.get(@enumFromInt(file.scope.index)); + if (&threads[file.thread] == thread) { + exit_with_error("Threads match!"); + } else { + const pending_file_index = for (thread.pending_files.slice(), 0..) |pending_file_path_hash, i| { + if (file_path_hash == pending_file_path_hash) { + break i; + } + } else { + exit(1); + }; + // _ = pending_file_index; // autofix + + const pending_file_values = thread.pending_file_values.get(@enumFromInt(pending_file_index)); + + for (pending_file_values.slice()) |value| { + assert(value.sema.thread == thread.get_index()); + if (!value.sema.resolved) { + switch (value.sema.id) { + .instruction => { + const instruction = thread.instructions.get(@enumFromInt(value.sema.index)); + switch (instruction.id) { + .call => { + const call = thread.calls.get(@enumFromInt(instruction.index)); + const callable = call.value; + assert(!callable.sema.resolved); + switch (callable.sema.id) { + .lazy_expression => { + const lazy_expression = thread.lazy_expressions.get(@enumFromInt(callable.sema.index)); + assert(lazy_expression.* == .static); + const names = lazy_expression.names(); + assert(names.len > 0); + const declaration = lazy_expression.static.outsider; + switch (declaration.id) { + .file => {}, + // .unresolved_import => { + // assert(declaration.index == pending_file_index); + // declaration.id = .file; + // declaration.index = file_index; + // value.resolved = true; + // unreachable; + // }, + else => |t| @panic(@tagName(t)), + } + + assert(names.len == 1); + + if (file_scope.declarations.get(names[0])) |callable_declaration| switch (callable_declaration.id) { + .function_definition => { + const function_definition = threads[file.thread].functions.get_unchecked(callable_declaration.index); + const external_fn = thread.external_functions.append(function_definition.declaration); + external_fn.global.attributes.@"export" = false; + external_fn.global.attributes.@"extern" = true; + + const new_callable_declaration = GlobalSymbolReference{ + .id = .function_declaration, + .index = @intCast(thread.external_functions.get_index(external_fn)), + }; + + const new_callable_value = thread.values.append(.{ + .sema = .{ + .id = .global_symbol, + .index = @bitCast(new_callable_declaration), + .thread = thread.get_index(), + .resolved = true, + }, + }); + call.value = new_callable_value; + value.sema.resolved = true; + }, + else => |t| @panic(@tagName(t)), + // unreachable; + // // const new_callable_value = thread.values.append(.{ + // // .id = .global_symbol, + // // .index = @bitCast(callable_declaration), + // // .thread = @intCast(file.thread), + // // .resolved = true, + // // }); + // // call.value = new_callable_value; + // // value.resolved = true; + } else exit(1); + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + }, + .lazy_expression => { + const lazy_expression = thread.lazy_expressions.get(@enumFromInt(value.sema.index)); + assert(lazy_expression.* == .static); + for ( lazy_expression.static.names) |n| { + assert(n == 0); + } + const declaration = lazy_expression.static.outsider; + switch (declaration.id) { + .unresolved_import => { + assert(declaration.index == pending_file_index); + declaration.id = .file; + declaration.index = file_index; + value.sema.resolved = true; + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + } + } + } + }, + .resolve_thread_module => { + // exit(0); + }, + .llvm_codegen_thread_module => { + if (thread.functions.length > 0) { + const debug_info = true; + + const ExternalRef = struct{ + gsr: GlobalSymbolReference, + thread: u16, + }; + var external_hashmap = PinnedHashMap(ExternalRef, *LLVM.Value.Constant.Function){}; + + for (thread.external_functions.slice()) |*nat_function| { + _ = llvm_get_function(thread, nat_function, true); + } + + _ = &external_hashmap; // autofix + for (thread.functions.slice()) |*nat_function| { + _ = llvm_get_function(thread, &nat_function.declaration, false); + } + + for (thread.functions.slice()) |*nat_function| { + const function = nat_function.declaration.llvm.?; + const nat_entry_basic_block = thread.basic_blocks.get(nat_function.entry_block); + assert(nat_entry_basic_block.predecessors.length == 0); + const entry_block_name = "entry_block_name"; + const entry_block = thread.llvm.context.createBasicBlock(entry_block_name, entry_block_name.len, function, null); + thread.llvm.builder.setInsertPoint(entry_block); + + for (nat_entry_basic_block.instructions.slice()) |instruction| { + const value: *LLVM.Value = switch (instruction.id) { + .ret => block: { + const return_instruction = thread.returns.get(@enumFromInt(instruction.index)); + const return_value = llvm_get_value(thread, return_instruction.value); + const ret = thread.llvm.builder.createRet(return_value); + break :block ret.toValue(); + }, + .call => block: { + const call = thread.calls.get(@enumFromInt(instruction.index)); + const callee = if (call.value.sema.thread == thread.get_index()) switch (call.value.sema.id) { + .global_symbol => blk: { + const global_symbol: GlobalSymbolReference = @bitCast(call.value.sema.index); + break :blk switch (global_symbol.id) { + .function_declaration => b: { + const external_function = thread.external_functions.slice()[global_symbol.index]; + break :b external_function.llvm.?; + }, + else => |t| @panic(@tagName(t)), + }; + }, + else => |t| @panic(@tagName(t)), + } else exit(1); + const function_type = callee.getType(); + + const arguments: []const *LLVM.Value = &.{}; + const call_i = thread.llvm.builder.createCall(function_type, callee.toValue(), arguments.ptr, arguments.len, "", "".len, null); + break :block call_i.toValue(); + }, + else => |t| @panic(@tagName(t)), + }; + + instruction.llvm = value; + } + + if (debug_info) { + const file_index = nat_function.declaration.file; + const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?; + const subprogram = function.getSubprogram(); + llvm_file.builder.finalizeSubprogram(subprogram, function); + } + + const verify_function = true; + if (verify_function) { + var message: []const u8 = undefined; + const verification_success = function.verify(&message.ptr, &message.len); + if (!verification_success) { + var function_msg: []const u8 = undefined; + function.toString(&function_msg.ptr, &function_msg.len); + write(function_msg); + write("\n"); + exit_with_error(message); + } + } + } + + if (debug_info) { + const file_index = thread.functions.slice()[0].declaration.file; + const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?; + llvm_file.builder.finalize(); + } + + const verify_module = true; + if (verify_module) { + var verification_message: []const u8 = undefined; + const verification_success = thread.llvm.module.verify(&verification_message.ptr, &verification_message.len); + if (!verification_success) { + const print_module = true; + if (print_module) { + var module_content: []const u8 = undefined; + thread.llvm.module.toString(&module_content.ptr, &module_content.len); + write(module_content); + write("\n"); + } + + exit_with_error(verification_message); + } + } + } + }, + } + + thread.task_system.job.completed += 1; + } + } + + std.atomic.spinLoopHint(); + } +} + +fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value { + if (value.llvm) |llvm| return llvm else { + const value_id = value.sema.id; + const llvm_value: *LLVM.Value = switch (value_id) { + .constant_int => b: { + const constant_int = thread.constant_ints.get(@enumFromInt(value.sema.index)); + const integer_value = constant_int.value; + const bit_count = integer_bit_count(constant_int.type); + const signedness = integer_signedness(constant_int.type); + const result = thread.llvm.context.getConstantInt(bit_count, integer_value, @intFromEnum(signedness) != 0); + break :b result.toValue(); + }, + .lazy_expression => { + // const lazy_expression = thread.expressions.get(@enumFromInt(value.index)); + // switch (lazy_expression.kind) { + // .resolved => |resolved| switch (resolved) { + // .instruction => |instruction| switch (instruction.id) { + // else => |t| @panic(@tagName(t)), + // }, + // else => |t| @panic(@tagName(t)), + // }, + // else => |t| @panic(@tagName(t)), + // } + @trap(); + }, + .instruction => block: { + const instruction = thread.instructions.get_unchecked(value.sema.index); + break :block instruction.llvm.?; + }, + else => |t| @panic(@tagName(t)), + }; + + value.llvm = llvm_value; + + return llvm_value; + } +} + +fn llvm_get_type(thread: *Thread, ty: *Type) *LLVM.Type { + var store = true; + if (ty.llvm) |llvm| { + if (llvm.getContext() == thread.llvm.context) { + return llvm; + } + store = false; + } + + { + const llvm_type: *LLVM.Type = switch (ty.sema.id) { + .integer => b: { + const bit_count = integer_bit_count(ty); + const integer_type = thread.llvm.context.getIntegerType(bit_count); + break :b integer_type.toType(); + }, + else => |t| @panic(@tagName(t)), + }; + if (store) { + ty.llvm = llvm_type; + } + return llvm_type; + } +} + +fn llvm_get_file(thread: *Thread, file_index: u32) *LLVMFile { + if (thread.debug_info_file_map.get_pointer(file_index)) |llvm| return llvm else { + const builder = thread.llvm.module.createDebugInfoBuilder(); + const file = &instance.files.slice()[file_index]; + const filename = std.fs.path.basename(file.path); + const directory = file.path[0..file.path.len - filename.len]; + const llvm_file = builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len); + const producer = "nativity"; + const is_optimized = false; + const flags = ""; + const runtime_version = 0; + const splitname = ""; + const DWOId = 0; + const debug_info_kind = LLVM.DebugInfo.CompileUnit.EmissionKind.full_debug; + const split_debug_inlining = true; + const debug_info_for_profiling = false; + const name_table_kind = LLVM.DebugInfo.CompileUnit.NameTableKind.default; + const ranges_base_address = false; + const sysroot = ""; + const sdk = ""; + const compile_unit = builder.createCompileUnit(LLVM.DebugInfo.Language.c, llvm_file, producer, producer.len, is_optimized, flags, flags.len, runtime_version, splitname, splitname.len, debug_info_kind, DWOId, split_debug_inlining, debug_info_for_profiling, name_table_kind, ranges_base_address, sysroot, sysroot.len, sdk, sdk.len); + + thread.debug_info_file_map.put_no_clobber(file_index, .{ + .file = llvm_file, + .compile_unit = compile_unit, + .builder = builder, + }); + + return thread.debug_info_file_map.get_pointer(file_index).?; + } +} + +fn llvm_get_function(thread: *Thread, nat_function: *Function.Declaration, override_extern: bool) *LLVM.Value.Constant.Function { + if (nat_function.llvm) |llvm| return llvm else { + _ = override_extern; // autofix + const function_name = thread.identifiers.get(nat_function.global.name) orelse unreachable; + const return_type = llvm_get_type(thread, nat_function.return_type); + var argument_types = PinnedArray(*LLVM.Type){}; + _ = &argument_types; + for (nat_function.argument_types) |argument_type| { + _ = argument_type; // autofix + exit(1); + } + const is_var_args = false; + const function_type = LLVM.getFunctionType(return_type, argument_types.pointer, argument_types.length, is_var_args); + const is_extern_function = nat_function.global.attributes.@"extern"; + const export_or_extern = nat_function.global.attributes.@"export" or is_extern_function; + const linkage: LLVM.Linkage = switch (export_or_extern) { + true => .@"extern", + false => .internal, + }; + const function = thread.llvm.module.createFunction(function_type, linkage, address_space, function_name.ptr, function_name.len); + + const debug_info = true; + if (debug_info) { + const file_index = nat_function.file; + const llvm_file = llvm_get_file(thread, file_index); + var debug_argument_types = PinnedArray(*LLVM.DebugInfo.Type){}; + _ = &debug_argument_types; + for (nat_function.argument_types) |argument_type| { + _ = argument_type; // autofix + exit(1); + } + + const subroutine_type_flags = LLVM.DebugInfo.Node.Flags{ + .visibility = .none, + .forward_declaration = is_extern_function, + .apple_block = false, + .block_by_ref_struct = false, + .virtual = false, + .artificial = false, + .explicit = false, + .prototyped = false, + .objective_c_class_complete = false, + .object_pointer = false, + .vector = false, + .static_member = false, + .lvalue_reference = false, + .rvalue_reference = false, + .reserved = false, + .inheritance = .none, + .introduced_virtual = false, + .bit_field = false, + .no_return = false, + .type_pass_by_value = false, + .type_pass_by_reference = false, + .enum_class = false, + .thunk = false, + .non_trivial = false, + .big_endian = false, + .little_endian = false, + .all_calls_described = false, + }; + const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none; + const subroutine_type = llvm_file.builder.createSubroutineType(debug_argument_types.pointer, debug_argument_types.length, subroutine_type_flags, subroutine_type_calling_convention); + const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{ + .virtuality = .none, + .local_to_unit = !export_or_extern, + .definition = !is_extern_function, + .optimized = false, + .pure = false, + .elemental = false, + .recursive = false, + .main_subprogram = false, + .deleted = false, + .object_c_direct = false, + }; + const subprogram_declaration = null; + const file = llvm_file.file; + const scope = file.toScope(); + const line = 0; + const scope_line = 0; + + const subprogram = llvm_file.builder.createFunction(scope, function_name.ptr, function_name.len, function_name.ptr, function_name.len, file, line, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration); + function.setSubprogram(subprogram); + } + + nat_function.llvm = function; + return function; + } +} + +pub fn analyze_file(thread: *Thread, file_index: u32) void { + const file = instance.files.get(@enumFromInt(file_index)); + const src = file.source_code; + if (src.len > std.math.maxInt(u32)) { + exit(1); + } + + file.functions.start = @intCast(thread.functions.length); + + var parser = Parser{}; + var analyzer = Analyzer{}; + + while (true) { + parser.skip_space(src); + + if (parser.i >= src.len) break; + + const declaration_start_i = parser.i; + const declaration_start_ch = src[declaration_start_i]; + + switch (declaration_start_ch) { + '>' => { + parser.i += 1; + parser.skip_space(src); + const symbol_identifier_start = parser.i; + _ = symbol_identifier_start; // autofix + const identifier = parser.parse_identifier(thread, src); + _ = identifier; // autofix + + + exit(1); + }, + 'f' => { + if (src[parser.i + 1] == 'n') { + parser.i += 2; + parser.skip_space(src); + + const function = thread.functions.add_one(); + const function_index = thread.functions.get_index(function); + const entry_block = thread.basic_blocks.append(.{}); + const entry_block_index = thread.basic_blocks.get_typed_index(entry_block); + + analyzer.current_function = function; + analyzer.current_basic_block = entry_block; + + function.* = .{ + .declaration = .{ + .return_type = undefined, + .global = .{ + .name = undefined, + }, + .file = file_index, + }, + .entry_block = entry_block_index, + }; + + const has_function_attributes = src[parser.i] == '['; + parser.i += @intFromBool(has_function_attributes); + + if (has_function_attributes) { + var attribute_mask = Function.Attribute.Mask.initEmpty(); + + while (true) { + parser.skip_space(src); + + if (src[parser.i] == ']') break; + + const attribute_identifier = parser.parse_raw_identifier(src); + b: inline for (@typeInfo(Function.Attribute).Enum.fields) |fa_field| { + if (byte_equal(fa_field.name, attribute_identifier)) { + const function_attribute = @field(Function.Attribute, fa_field.name); + if (attribute_mask.contains(function_attribute)) { + exit(1); + } + + attribute_mask.setPresent(function_attribute, true); + + switch (function_attribute) { + .cc => { + parser.skip_space(src); + + parser.expect_character(src, '('); + + parser.skip_space(src); + + parser.expect_character(src, '.'); + + const cc_identifier = parser.parse_raw_identifier(src); + + parser.skip_space(src); + + parser.expect_character(src, ')'); + + inline for (@typeInfo(CallingConvention).Enum.fields) |cc_field| { + if (byte_equal(cc_field.name, cc_identifier)) { + const calling_convention = @field(CallingConvention, cc_field.name); + function.declaration.attributes.calling_convention = calling_convention; + break :b; + } + } else { + exit(1); + } + }, + } + } + } else { + exit(1); + } + + parser.skip_space(src); + + const after_ch = src[parser.i]; + switch (after_ch) { + ']' => {}, + else => unreachable, + } + } + + parser.i += 1; + + parser.skip_space(src); + } + + function.declaration.global.name = parser.parse_identifier(thread, src); + + parser.skip_space(src); + + const has_symbol_attributes = src[parser.i] == '['; + parser.i += @intFromBool(has_symbol_attributes); + + if (has_symbol_attributes) { + var attribute_mask = GlobalSymbol.Attribute.Mask.initEmpty(); + + while (true) { + parser.skip_space(src); + + if (src[parser.i] == ']') break; + + const attribute_identifier = parser.parse_raw_identifier(src); + inline for (@typeInfo(GlobalSymbol.Attribute).Enum.fields) |fa_field| { + if (byte_equal(fa_field.name, attribute_identifier)) { + const global_attribute = @field(GlobalSymbol.Attribute, fa_field.name); + if (attribute_mask.contains(global_attribute)) { + exit(1); + } + + attribute_mask.setPresent(global_attribute, true); + + switch (global_attribute) { + .@"export" => {}, + .@"extern" => {}, + } + + const after_ch =src[parser.i]; + switch (after_ch) { + ']' => {}, + else => unreachable, + } + + break; + } + } else { + exit(1); + } + + parser.skip_space(src); + + const after_ch = src[parser.i]; + switch (after_ch) { + ']' => {}, + else => unreachable, + } + } + + parser.i += 1; + + parser.skip_space(src); + } + + const split_modules = true; + if (split_modules) { + function.declaration.global.attributes.@"export" = true; + } + + parser.expect_character(src, '('); + + while (true) { + parser.skip_space(src); + + if (src[parser.i] == ')') break; + + exit(1); + } + + parser.expect_character(src, ')'); + + parser.skip_space(src); + + function.declaration.return_type = parser.parse_type_expression(thread, src); + + parser.skip_space(src); + + const block_start = parser.i; + const block_line = parser.current_line + 1; + _ = block_line; // autofix + const block_column = block_start - parser.line_offset + 1; + _ = block_column; // autofix + // + parser.expect_character(src, bracket_open); + const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index)); + file_scope.declarations.put_no_clobber(function.declaration.global.name, .{ + .id = .function_definition, + .index = @intCast(function_index), + }); + + parser.skip_space(src); + + while (true) { + parser.skip_space(src); + + if (src[parser.i] == bracket_close) break; + + if (src[parser.i] == 'r') { + const identifier = parser.parse_raw_identifier(src); + + if (byte_equal(identifier, "return")) { + parser.skip_space(src); + + if (function.declaration.return_type.sema.id != .unresolved) { + const return_value = parser.parse_typed_expression(&analyzer, thread, file, function.declaration.return_type); + parser.expect_character(src, ';'); + + + const return_expression = thread.returns.append_index(.{ + .value = return_value, + }); + + const return_instruction = thread.instructions.append(.{ + .id = .ret, + .index = @intCast(return_expression), + }); + + _ = analyzer.current_basic_block.instructions.append(return_instruction); + analyzer.current_basic_block.is_terminated = true; + } else { + exit(1); + } + } else { + exit(1); + } + } else { + exit(1); + } + } + + parser.expect_character(src, bracket_close); + } else { + exit(1); + } + }, + 'i' => { + const import_keyword = "import"; + if (byte_equal(src[parser.i..][0..import_keyword.len], import_keyword)) { + parser.i += import_keyword.len; + + parser.skip_space(src); + + const string_literal = parser.parse_non_escaped_string_literal_content(src); + parser.skip_space(src); + + parser.expect_character(src, ';'); + + const filename = std.fs.path.basename(string_literal); + const has_right_extension = filename.len > ".nat".len and byte_equal(filename[filename.len - ".nat".len..], ".nat"); + if (!has_right_extension) { + exit(1); + } + const filename_without_extension = filename[0..filename.len - ".nat".len]; + const filename_without_extension_hash = hash_bytes(filename_without_extension); + + const directory_path = file.get_directory_path(); + const directory = std.fs.openDirAbsolute(directory_path, .{}) catch unreachable; + const file_path = library.realpath(thread.arena, directory, string_literal) catch unreachable; + const file_path_hash = intern_identifier(&thread.identifiers, file_path); + + if (thread.local_files.get(file_path_hash)) |import_file_index| { + _ = import_file_index; // autofix + exit(1); + } else { + for (thread.pending_files.slice()) |pending_file| { + if (pending_file == file_path_hash) { + exit(1); + } + } else { + thread.add_control_work(.{ + .id = .analyze_file, + .offset = file_path_hash, + }); + const index = thread.pending_files.append_index(file_path_hash); + const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index)); + file_scope.declarations.put_no_clobber(filename_without_extension_hash, .{ + .id = .unresolved_import, + .index = @intCast(index), + }); + const ptr = file_scope.declarations.get_pointer(filename_without_extension_hash) orelse unreachable; + const list = thread.pending_file_values.append(.{}); + const lazy_expression = thread.lazy_expressions.append(LazyExpression.init(ptr)); + const declaration = thread.values.append(.{ + .sema = .{ + .id = .lazy_expression, + .index = thread.lazy_expressions.get_index(lazy_expression), + .thread = thread.get_index(), + .resolved = false, + }, + }); + _ = list.append(declaration); + } + } + } else { + exit(1); + } + }, + else => exit(1), + } + } +} + +pub const LLVM = struct { + const bindings = @import("backend/llvm_bindings.zig"); + 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, + nounwind: *Attribute, + inreg: *Attribute, + @"noalias": *Attribute, + }; + + pub const Linkage = enum(c_uint) { + @"extern" = 0, + available_external = 1, + link_once_any = 2, + link_once_odr = 3, + weak_any = 4, + weak_odr = 5, + appending = 6, + internal = 7, + private = 8, + external_weak = 9, + common = 10, + }; + + pub const ThreadLocalMode = enum(c_uint) { + not_thread_local = 0, + }; + + const getFunctionType = bindings.NativityLLVMGetFunctionType; + + pub const Context = opaque { + const create = bindings.NativityLLVMCreateContext; + const createBasicBlock = bindings.NativityLLVMCreateBasicBlock; + const getConstantInt = bindings.NativityLLVMContextGetConstantInt; + const getConstString = bindings.NativityLLVMContextGetConstString; + const getVoidType = bindings.NativityLLVMGetVoidType; + const getIntegerType = bindings.NativityLLVMGetIntegerType; + const getPointerType = bindings.NativityLLVMGetPointerType; + const getStructType = bindings.NativityLLVMGetStructType; + const getIntrinsicType = bindings.NativityLLVMContextGetIntrinsicType; + const getAttributeFromEnum = bindings.NativityLLVMContextGetAttributeFromEnum; + const getAttributeFromString = bindings.NativityLLVMContextGetAttributeFromString; + const getAttributeFromType = bindings.NativityLLVMContextGetAttributeFromType; + const getAttributeSet = bindings.NativityLLVMContextGetAttributeSet; + }; + + pub const Module = opaque { + const addGlobalVariable = bindings.NativityLLVMModuleAddGlobalVariable; + const create = bindings.NativityLLVMCreateModule; + const getFunction = bindings.NativityLLVMModuleGetFunction; + const createFunction = bindings.NativityLLVModuleCreateFunction; + const verify = bindings.NativityLLVMVerifyModule; + const toString = bindings.NativityLLVMModuleToString; + const getIntrinsicDeclaration = bindings.NativityLLVMModuleGetIntrinsicDeclaration; + const createDebugInfoBuilder = bindings.NativityLLVMModuleCreateDebugInfoBuilder; + const setTargetMachineDataLayout = bindings.NativityLLVMModuleSetTargetMachineDataLayout; + const setTargetTriple = bindings.NativityLLVMModuleSetTargetTriple; + const runOptimizationPipeline = bindings.NativityLLVMRunOptimizationPipeline; + const addPassesToEmitFile = bindings.NativityLLVMModuleAddPassesToEmitFile; + const link = bindings.NativityLLVMLinkModules; + }; + + pub const LinkFlags = packed struct(c_uint) { + override_from_source: bool, + link_only_needed: bool, + _: u30 = 0, + }; + + pub const Builder = opaque { + const create = bindings.NativityLLVMCreateBuilder; + const setInsertPoint = bindings.NativityLLVMBuilderSetInsertPoint; + const createAdd = bindings.NativityLLVMBuilderCreateAdd; + const createAlloca = bindings.NativityLLVMBuilderCreateAlloca; + const createAnd = bindings.NativityLLVMBuilderCreateAnd; + const createOr = bindings.NativityLLVMBuilderCreateOr; + const createCall = bindings.NativityLLVMBuilderCreateCall; + const createCast = bindings.NativityLLVMBuilderCreateCast; + const createBranch = bindings.NativityLLVMBuilderCreateBranch; + const createConditionalBranch = bindings.NativityLLVMBuilderCreateConditionalBranch; + const createSwitch = bindings.NativityLLVMBuilderCreateSwitch; + const createGEP = bindings.NativityLLVMBuilderCreateGEP; + const createStructGEP = bindings.NativityLLVMBuilderCreateStructGEP; + const createICmp = bindings.NativityLLVMBuilderCreateICmp; + const createLoad = bindings.NativityLLVMBuilderCreateLoad; + const createMultiply = bindings.NativityLLVMBuilderCreateMultiply; + const createRet = bindings.NativityLLVMBuilderCreateRet; + const createShiftLeft = bindings.NativityLLVMBuilderCreateShiftLeft; + const createArithmeticShiftRight = bindings.NativityLLVMBuilderCreateArithmeticShiftRight; + const createLogicalShiftRight = bindings.NativityLLVMBuilderCreateLogicalShiftRight; + const createStore = bindings.NativityLLVMBuilderCreateStore; + const createSub = bindings.NativityLLVMBuilderCreateSub; + const createUnreachable = bindings.NativityLLVMBuilderCreateUnreachable; + const createXor = bindings.NativityLLVMBuilderCreateXor; + const createUDiv = bindings.NativityLLVMBuilderCreateUDiv; + const createSDiv = bindings.NativityLLVMBuilderCreateSDiv; + const createURem = bindings.NativityLLVMBuilderCreateURem; + const createSRem = bindings.NativityLLVMBuilderCreateSRem; + const createExtractValue = bindings.NativityLLVMBuilderCreateExtractValue; + const createInsertValue = bindings.NativityLLVMBuilderCreateInsertValue; + const createGlobalString = bindings.NativityLLVMBuilderCreateGlobalString; + const createGlobalStringPointer = bindings.NativityLLVMBuilderCreateGlobalStringPointer; + const createPhi = bindings.NativityLLVMBuilderCreatePhi; + const createMemcpy = bindings.NativityLLVMBuilderCreateMemcpy; + + const getInsertBlock = bindings.NativityLLVMBuilderGetInsertBlock; + const isCurrentBlockTerminated = bindings.NativityLLVMBuilderIsCurrentBlockTerminated; + const setCurrentDebugLocation = bindings.NativityLLVMBuilderSetCurrentDebugLocation; + }; + + pub const DebugInfo = struct { + pub const AttributeType = enum(c_uint) { + address = 0x01, + boolean = 0x02, + complex_float = 0x03, + float = 0x04, + signed = 0x05, + signed_char = 0x06, + unsigned = 0x07, + unsigned_char = 0x08, + imaginary_float = 0x09, + packed_decimal = 0x0a, + numeric_string = 0x0b, + edited = 0x0c, + signed_fixed = 0x0d, + unsigned_fixed = 0x0e, + decimal_float = 0x0f, + UTF = 0x10, + UCS = 0x11, + ASCII = 0x12, + }; + + pub const CallingConvention = enum(c_uint) { + none = 0, + normal = 0x01, + program = 0x02, + nocall = 0x03, + pass_by_reference = 0x04, + pass_by_value = 0x05, + // Vendor extensions + GNU_renesas_sh = 0x40, + GNU_borland_fastcall_i386 = 0x41, + BORLAND_safecall = 0xb0, + BORLAND_stdcall = 0xb1, + BORLAND_pascal = 0xb2, + BORLAND_msfastcall = 0xb3, + BORLAND_msreturn = 0xb4, + BORLAND_thiscall = 0xb5, + BORLAND_fastcall = 0xb6, + LLVM_vectorcall = 0xc0, + LLVM_Win64 = 0xc1, + LLVM_X86_64SysV = 0xc2, + LLVM_AAPCS = 0xc3, + LLVM_AAPCS_VFP = 0xc4, + LLVM_IntelOclBicc = 0xc5, + LLVM_SpirFunction = 0xc6, + LLVM_OpenCLKernel = 0xc7, + LLVM_Swift = 0xc8, + LLVM_PreserveMost = 0xc9, + LLVM_PreserveAll = 0xca, + LLVM_X86RegCall = 0xcb, + GDB_IBM_OpenCL = 0xff, + }; + + pub const Builder = opaque { + const createCompileUnit = bindings.NativityLLVMDebugInfoBuilderCreateCompileUnit; + const createFile = bindings.NativityLLVMDebugInfoBuilderCreateFile; + const createFunction = bindings.NativityLLVMDebugInfoBuilderCreateFunction; + const createSubroutineType = bindings.NativityLLVMDebugInfoBuilderCreateSubroutineType; + const createLexicalBlock = bindings.NativityLLVMDebugInfoBuilderCreateLexicalBlock; + const createParameterVariable = bindings.NativityLLVMDebugInfoBuilderCreateParameterVariable; + const createAutoVariable = bindings.NativityLLVMDebugInfoBuilderCreateAutoVariable; + const createGlobalVariableExpression = bindings.NativityLLVMDebugInfoBuilderCreateGlobalVariableExpression; + const createExpression = bindings.NativityLLVMDebugInfoBuilderCreateExpression; + const createBasicType = bindings.NativityLLVMDebugInfoBuilderCreateBasicType; + const createPointerType = bindings.NativityLLVMDebugInfoBuilderCreatePointerType; + const createStructType = bindings.NativityLLVMDebugInfoBuilderCreateStructType; + const createArrayType = bindings.NativityLLVMDebugInfoBuilderCreateArrayType; + const createEnumerationType = bindings.NativityLLVMDebugInfoBuilderCreateEnumerationType; + const createEnumerator = bindings.NativityLLVMDebugInfoBuilderCreateEnumerator; + const createReplaceableCompositeType = bindings.NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType; + const createMemberType = bindings.NativityLLVMDebugInfoBuilderCreateMemberType; + const insertDeclare = bindings.NativityLLVMDebugInfoBuilderInsertDeclare; + const finalizeSubprogram = bindings.NativityLLVMDebugInfoBuilderFinalizeSubprogram; + const finalize = bindings.NativityLLVMDebugInfoBuilderFinalize; + const replaceCompositeTypes = bindings.NativityLLVMDebugInfoBuilderCompositeTypeReplaceTypes; + }; + + pub const CompileUnit = opaque { + fn toScope(this: *@This()) *LLVM.DebugInfo.Scope { + return @ptrCast(this); + } + + pub const EmissionKind = enum(c_uint) { + no_debug = 0, + full_debug = 1, + line_tables_only = 2, + debug_directives_only = 3, + }; + + pub const NameTableKind = enum(c_uint) { + default = 0, + gnu = 1, + none = 2, + }; + }; + + pub const Expression = opaque {}; + + pub const GlobalVariableExpression = opaque {}; + + pub const LocalVariable = opaque {}; + pub const LexicalBlock = opaque { + fn toScope(this: *@This()) *LLVM.DebugInfo.Scope { + return @ptrCast(this); + } + }; + + pub const Node = opaque { + pub const Flags = packed struct(u32) { + visibility: Visibility, + forward_declaration: bool, + apple_block: bool, + block_by_ref_struct: bool, + virtual: bool, + artificial: bool, + explicit: bool, + prototyped: bool, + objective_c_class_complete: bool, + object_pointer: bool, + vector: bool, + static_member: bool, + lvalue_reference: bool, + rvalue_reference: bool, + reserved: bool = false, + inheritance: Inheritance, + introduced_virtual: bool, + bit_field: bool, + no_return: bool, + type_pass_by_value: bool, + type_pass_by_reference: bool, + enum_class: bool, + thunk: bool, + non_trivial: bool, + big_endian: bool, + little_endian: bool, + all_calls_described: bool, + _: 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 File = opaque { + fn toScope(this: *@This()) *LLVM.DebugInfo.Scope { + return @ptrCast(this); + } + }; + + pub const Language = enum(c_uint) { + c = 0x02, + }; + + pub const Scope = opaque { + const toSubprogram = bindings.NativityLLVMDebugInfoScopeToSubprogram; + }; + + pub const LocalScope = opaque { + fn toScope(this: *@This()) *LLVM.DebugInfo.Scope { + return @ptrCast(this); + } + }; + pub const Subprogram = opaque { + const getFile = bindings.NativityLLVMDebugInfoSubprogramGetFile; + const getArgumentType = bindings.NativityLLVMDebugInfoSubprogramGetArgumentType; + fn toLocalScope(this: *@This()) *LocalScope { + return @ptrCast(this); + } + + pub const Flags = packed struct(u32) { + virtuality: Virtuality, + local_to_unit: bool, + definition: bool, + optimized: bool, + pure: bool, + elemental: bool, + recursive: bool, + main_subprogram: bool, + deleted: bool, + reserved: bool = false, + object_c_direct: bool, + _: u20 = 0, + + const Virtuality = enum(u2) { + none = 0, + virtual = 1, + pure_virtual = 2, + }; + }; + }; + + pub const Type = opaque { + const isResolved = bindings.NativityLLLVMDITypeIsResolved; + fn toScope(this: *@This()) *LLVM.DebugInfo.Scope { + return @ptrCast(this); + } + + pub const Derived = opaque { + fn toType(this: *@This()) *LLVM.DebugInfo.Type { + return @ptrCast(this); + } + }; + + pub const Composite = opaque { + fn toType(this: *@This()) *LLVM.DebugInfo.Type { + return @ptrCast(this); + } + }; + + pub const Enumerator = opaque {}; + pub const Subroutine = opaque { + fn toType(this: *@This()) *LLVM.DebugInfo.Type { + return @ptrCast(this); + } + }; + }; + }; + + pub const FloatAbi = enum(c_uint) { + default = 0, + soft = 1, + hard = 2, + }; + + pub const FloatOperationFusionMode = enum(c_uint) { + fast = 0, + standard = 1, + strict = 2, + }; + + pub const JumpTableType = enum(c_uint) { + single = 0, + arity = 1, + simplified = 2, + full = 3, + }; + + pub const ThreadModel = enum(c_uint) { + posix = 0, + single = 1, + }; + + pub const BasicBlockSection = enum(c_uint) { + all = 0, + list = 1, + labels = 2, + preset = 3, + none = 4, + }; + + pub const EAbi = enum(c_uint) { + unknown = 0, + default = 1, + eabi4 = 2, + eabi5 = 3, + gnu = 4, + }; + + pub const DebuggerKind = enum(c_uint) { + default = 0, + gdb = 1, + lldb = 2, + sce = 3, + dbx = 4, + }; + + pub const GlobalISelAbortMode = enum(c_uint) { + disable = 0, + enable = 1, + disable_with_diagnostic = 2, + }; + + pub const DebugCompressionType = enum(c_uint) { + none = 0, + zlib = 1, + zstd = 2, + }; + + pub const RelocationModel = enum(c_uint) { + static = 0, + pic = 1, + dynamic_no_pic = 2, + ropi = 3, + rwpi = 4, + ropi_rwpi = 5, + }; + + pub const CodeModel = enum(c_uint) { + tiny = 0, + small = 1, + kernel = 2, + medium = 3, + large = 4, + }; + + pub const PicLevel = enum(c_uint) { + not_pic = 0, + small_pic = 1, + big_pic = 2, + }; + + pub const PieLevel = enum(c_uint) { + default = 0, + small = 1, + large = 2, + }; + + pub const TlsModel = enum(c_uint) { + general_dynamic = 0, + local_dynamic = 1, + initial_exec = 2, + local_exec = 3, + }; + + pub const CodegenOptimizationLevel = enum(c_int) { + none = 0, + less = 1, + default = 2, + 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, + all = 2, + }; + + pub const CodeGenFileType = enum(c_uint) { + assembly = 0, + object = 1, + null = 2, + }; + + pub const Target = opaque { + const createTargetMachine = bindings.NativityLLVMTargetCreateTargetMachine; + + pub const Machine = opaque {}; + + // This is a non-LLVM struct + const Options = extern struct { + bin_utils_version: struct { i32, i32 }, + fp_math: extern struct { + unsafe: bool, + no_infs: bool, + no_nans: bool, + no_traping: bool, + no_signed_zeroes: bool, + approx_func: bool, + enable_aix_extended_altivec_abi: bool, + honor_sign_dependent_rounding: bool, + }, + no_zeroes_in_bss: bool, + guaranteed_tail_call_optimization: bool, + stack_symbol_ordering: bool, + enable_fast_isel: bool, + enable_global_isel: bool, + global_isel_abort_mode: GlobalISelAbortMode, + use_init_array: bool, + disable_integrated_assembler: bool, + debug_compression_type: DebugCompressionType, + relax_elf_relocations: bool, + function_sections: bool, + data_sections: bool, + ignore_xcoff_visibility: bool, + xcoff_traceback_table: bool, + unique_section_names: bool, + unique_basic_block_section_names: bool, + trap_unreachable: bool, + no_trap_after_noreturn: bool, + tls_size: u8, + emulated_tls: bool, + enable_ipra: bool, + emit_stack_size_section: bool, + enable_machine_outliner: bool, + enable_machine_function_splitter: bool, + support_default_outlining: bool, + emit_address_significance_table: bool, + bb_sections: BasicBlockSection, + emit_call_site_info: bool, + support_debug_entry_values: bool, + enable_debug_entry_values: bool, + value_tracking_variable_locations: bool, + force_dwarf_frame_section: bool, + xray_function_index: bool, + debug_strict_dwarf: bool, + hotpatch: bool, + ppc_gen_scalar_mass_entries: bool, + jmc_instrument: bool, + cfi_fixup: bool, + loop_alignment: u32 = 0, + float_abi_type: FloatAbi, + fp_operation_fusion: FloatOperationFusionMode, + thread_model: ThreadModel, + eabi_version: EAbi, + debugger_tuning: DebuggerKind, + }; + }; + + const lookupIntrinsic = bindings.NativityLLVMLookupIntrinsic; + const newPhiNode = bindings.NativityLLVMCreatePhiNode; + + pub const Metadata = opaque { + pub const Node = opaque {}; + pub const Tuple = opaque {}; + }; + + pub const Attribute = opaque { + pub const Set = opaque {}; + pub const Id = enum(u32) { + AllocAlign = 1, + AllocatedPointer = 2, + AlwaysInline = 3, + Builtin = 4, + Cold = 5, + Convergent = 6, + DisableSanitizerInstrumentation = 7, + FnRetThunkExtern = 8, + Hot = 9, + ImmArg = 10, + InReg = 11, + InlineHint = 12, + JumpTable = 13, + MinSize = 14, + MustProgress = 15, + Naked = 16, + Nest = 17, + NoAlias = 18, + NoBuiltin = 19, + NoCallback = 20, + NoCapture = 21, + NoCfCheck = 22, + NoDuplicate = 23, + NoFree = 24, + NoImplicitFloat = 25, + NoInline = 26, + NoMerge = 27, + NoProfile = 28, + NoRecurse = 29, + NoRedZone = 30, + NoReturn = 31, + NoSanitizeBounds = 32, + NoSanitizeCoverage = 33, + NoSync = 34, + NoUndef = 35, + NoUnwind = 36, + NonLazyBind = 37, + NonNull = 38, + NullPointerIsValid = 39, + OptForFuzzing = 40, + OptimizeForSize = 41, + OptimizeNone = 42, + PresplitCoroutine = 43, + ReadNone = 44, + ReadOnly = 45, + Returned = 46, + ReturnsTwice = 47, + SExt = 48, + SafeStack = 49, + SanitizeAddress = 50, + SanitizeHWAddress = 51, + SanitizeMemTag = 52, + SanitizeMemory = 53, + SanitizeThread = 54, + ShadowCallStack = 55, + SkipProfile = 56, + Speculatable = 57, + SpeculativeLoadHardening = 58, + StackProtect = 59, + StackProtectReq = 60, + StackProtectStrong = 61, + StrictFP = 62, + SwiftAsync = 63, + SwiftError = 64, + SwiftSelf = 65, + WillReturn = 66, + WriteOnly = 67, + ZExt = 68, + ByRef = 69, + ByVal = 70, + ElementType = 71, + InAlloca = 72, + Preallocated = 73, + StructRet = 74, + Alignment = 75, + AllocKind = 76, + AllocSize = 77, + Dereferenceable = 78, + DereferenceableOrNull = 79, + Memory = 80, + StackAlignment = 81, + UWTable = 82, + VScaleRange = 83, + }; + }; + + pub const Type = opaque { + const compare = bindings.NativityLLVMCompareTypes; + const toStruct = bindings.NativityLLVMTypeToStruct; + const toFunction = bindings.NativityLLVMTypeToFunction; + const toArray = bindings.NativityLLVMTypeToArray; + const toPointer = bindings.NativityLLVMTypeToPointer; + const isPointer = bindings.NativityLLVMTypeIsPointer; + const isInteger = bindings.NativityLLVMTypeIsInteger; + const isVoid = bindings.NativityLLVMTypeIsVoid; + const assertEqual = bindings.NativityLLVMTypeAssertEqual; + const getPoison = bindings.NativityLLVMGetPoisonValue; + const getContext = bindings.NativityLLVMTypeGetContext; + + pub const Array = opaque { + fn toType(integer: *@This()) *LLVM.Type { + return @ptrCast(integer); + } + const get = bindings.NativityLLVMGetArrayType; + const getConstant = bindings.NativityLLVMGetConstantArray; + const getElementType = bindings.NativityLLVMArrayTypeGetElementType; + }; + + pub const Integer = opaque { + fn toType(integer: *@This()) *LLVM.Type { + return @ptrCast(integer); + } + }; + + pub const Function = opaque { + fn toType(integer: *@This()) *LLVM.Type { + return @ptrCast(integer); + } + + const getArgumentType = bindings.NativityLLVMFunctionTypeGetArgumentType; + const getReturnType = bindings.NativityLLVMFunctionTypeGetReturnType; + }; + + pub const Pointer = opaque { + fn toType(integer: *@This()) *LLVM.Type { + return @ptrCast(integer); + } + + const getNull = bindings.NativityLLVMPointerTypeGetNull; + }; + + pub const Struct = opaque { + const getConstant = bindings.NativityLLVMGetConstantStruct; + fn toType(integer: *@This()) *LLVM.Type { + return @ptrCast(integer); + } + }; + + pub const Error = error{ + void, + function, + integer, + pointer, + @"struct", + intrinsic, + array, + }; + + }; + + pub const Value = opaque { + const setName = bindings.NativityLLVMValueSetName; + const getType = bindings.NativityLLVMValueGetType; + const toConstant = bindings.NativityLLVMValueToConstant; + const toFunction = bindings.NativityLLVMValueToFunction; + const toAlloca = bindings.NativityLLVMValueToAlloca; + const toString = bindings.NativityLLVMValueToString; + + pub const IntrinsicID = enum(u32) { + none = 0, + _, + }; + + pub const BasicBlock = opaque { + const remove = bindings.NativityLLVMBasicBlockRemoveFromParent; + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Argument = opaque { + const getIndex = bindings.NativityLLVMArgumentGetIndex; + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Instruction = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + + pub const Alloca = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + + const getAllocatedType = bindings.NativityLLVMAllocatGetAllocatedType; + }; + + pub const Branch = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Call = opaque { + const setCallingConvention = bindings.NativityLLVMCallSetCallingConvention; + const setAttributes = bindings.NativityLLVMCallSetAttributes; + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Cast = opaque { + pub const Type = enum(c_uint) { + truncate = 38, + zero_extend = 39, + sign_extend = 40, + float_to_unsigned_integer = 41, + float_to_signed_integer = 42, + unsigned_integer_to_float = 43, + signed_integer_to_float = 44, + float_truncate = 45, + float_extend = 46, + pointer_to_int = 47, + int_to_pointer = 48, + bitcast = 49, + address_space_cast = 50, + }; + + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const ICmp = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + + pub const Kind = enum(c_uint) { + eq = 32, // equal + ne = 33, // not equal + ugt = 34, // unsigned greater than + uge = 35, // unsigned greater or equal + ult = 36, // unsigned less than + ule = 37, // unsigned less or equal + sgt = 38, // signed greater than + sge = 39, // signed greater or equal + slt = 40, // signed less than + sle = 41, // signed less or equal + }; + }; + + pub const Load = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const PhiNode = opaque { + pub const addIncoming = bindings.NativityLLVMPhiAddIncoming; + + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Store = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Switch = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Ret = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Unreachable = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Error = error{ + add, + alloca, + @"and", + arithmetic_shift_right, + call, + cast, + conditional_branch, + extract_value, + gep, + icmp, + insert_value, + load, + logical_shift_right, + multiply, + @"or", + ret, + sdiv, + shift_left, + store, + udiv, + @"unreachable", + xor, + }; + }; + + pub const Constant = opaque { + pub const Function = opaque { + const getArgument = bindings.NativityLLVMFunctionGetArgument; + const getArguments = bindings.NativityLLVMFunctionGetArguments; + const getType = bindings.NativityLLVMFunctionGetType; + // const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey; + const verify = bindings.NativityLLVMVerifyFunction; + const toString = bindings.NativityLLVMFunctionToString; + const setCallingConvention = bindings.NativityLLVMFunctionSetCallingConvention; + const getCallingConvention = bindings.NativityLLVMFunctionGetCallingConvention; + const setSubprogram = bindings.NativityLLVMFunctionSetSubprogram; + const getSubprogram = bindings.NativityLLVMFunctionGetSubprogram; + const setAttributes = bindings.NativityLLVMFunctionSetAttributes; + + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + + pub const CallingConvention = enum(c_uint) { + /// The default llvm calling convention, compatible with C. This convention + /// is the only one that supports varargs calls. As with typical C calling + /// conventions, the callee/caller have to tolerate certain amounts of + /// prototype mismatch. + C = 0, + + // Generic LLVM calling conventions. None of these support varargs calls, + // and all assume that the caller and callee prototype exactly match. + + /// Attempts to make calls as fast as possible (e.g. by passing things in + /// registers). + Fast = 8, + + /// Attempts to make code in the caller as efficient as possible under the + /// assumption that the call is not commonly executed. As such, these calls + /// often preserve all registers so that the call does not break any live + /// ranges in the caller side. + Cold = 9, + + /// Used by the Glasgow Haskell Compiler (GHC). + GHC = 10, + + /// Used by the High-Performance Erlang Compiler (HiPE). + HiPE = 11, + + /// Used for stack based JavaScript calls + WebKit_JS = 12, + + /// Used for dynamic register based calls (e.g. stackmap and patchpoint + /// intrinsics). + AnyReg = 13, + + /// Used for runtime calls that preserves most registers. + PreserveMost = 14, + + /// Used for runtime calls that preserves (almost) all registers. + PreserveAll = 15, + + /// Calling convention for Swift. + Swift = 16, + + /// Used for access functions. + CXX_FAST_TLS = 17, + + /// Attemps to make calls as fast as possible while guaranteeing that tail + /// call optimization can always be performed. + Tail = 18, + + /// Special calling convention on Windows for calling the Control Guard + /// Check ICall funtion. The function takes exactly one argument (address of + /// the target function) passed in the first argument register, and has no + /// return value. All register values are preserved. + CFGuard_Check = 19, + + /// This follows the Swift calling convention in how arguments are passed + /// but guarantees tail calls will be made by making the callee clean up + /// their stack. + SwiftTail = 20, + + /// This is the start of the target-specific calling conventions, e.g. + /// fastcall and thiscall on X86. + // FirstTargetCC = 64, + + /// stdcall is mostly used by the Win32 API. It is basically the same as the + /// C convention with the difference in that the callee is responsible for + /// popping the arguments from the stack. + X86_StdCall = 64, + + /// 'fast' analog of X86_StdCall. Passes first two arguments in ECX:EDX + /// registers, others - via stack. Callee is responsible for stack cleaning. + X86_FastCall = 65, + + /// ARM Procedure Calling Standard (obsolete, but still used on some + /// targets). + ARM_APCS = 66, + + /// ARM Architecture Procedure Calling Standard calling convention (aka + /// EABI). Soft float variant. + ARM_AAPCS = 67, + + /// Same as ARM_AAPCS, but uses hard floating point ABI. + ARM_AAPCS_VFP = 68, + + /// Used for MSP430 interrupt routines. + MSP430_INTR = 69, + + /// Similar to X86_StdCall. Passes first argument in ECX, others via stack. + /// Callee is responsible for stack cleaning. MSVC uses this by default for + /// methods in its ABI. + X86_ThisCall = 70, + + /// Call to a PTX kernel. Passes all arguments in parameter space. + PTX_Kernel = 71, + + /// Call to a PTX device function. Passes all arguments in register or + /// parameter space. + PTX_Device = 72, + + /// Used for SPIR non-kernel device functions. No lowering or expansion of + /// arguments. Structures are passed as a pointer to a struct with the + /// byval attribute. Functions can only call SPIR_FUNC and SPIR_KERNEL + /// functions. Functions can only have zero or one return values. Variable + /// arguments are not allowed, except for printf. How arguments/return + /// values are lowered are not specified. Functions are only visible to the + /// devices. + SPIR_FUNC = 75, + + /// Used for SPIR kernel functions. Inherits the restrictions of SPIR_FUNC, + /// except it cannot have non-void return values, it cannot have variable + /// arguments, it can also be called by the host or it is externally + /// visible. + SPIR_KERNEL = 76, + + /// Used for Intel OpenCL built-ins. + Intel_OCL_BI = 77, + + /// The C convention as specified in the x86-64 supplement to the System V + /// ABI, used on most non-Windows systems. + X86_64_SysV = 78, + + /// The C convention as implemented on Windows/x86-64 and AArch64. It + /// differs from the more common \c X86_64_SysV convention in a number of + /// ways, most notably in that XMM registers used to pass arguments are + /// shadowed by GPRs, and vice versa. On AArch64, this is identical to the + /// normal C (AAPCS) calling convention for normal functions, but floats are + /// passed in integer registers to variadic functions. + Win64 = 79, + + /// MSVC calling convention that passes vectors and vector aggregates in SSE + /// registers. + X86_VectorCall = 80, + + /// Used by HipHop Virtual Machine (HHVM) to perform calls to and from + /// translation cache, and for calling PHP functions. HHVM calling + /// convention supports tail/sibling call elimination. + HHVM = 81, + + /// HHVM calling convention for invoking C/C++ helpers. + HHVM_C = 82, + + /// x86 hardware interrupt context. Callee may take one or two parameters, + /// where the 1st represents a pointer to hardware context frame and the 2nd + /// represents hardware error code, the presence of the later depends on the + /// interrupt vector taken. Valid for both 32- and 64-bit subtargets. + X86_INTR = 83, + + /// Used for AVR interrupt routines. + AVR_INTR = 84, + + /// Used for AVR signal routines. + AVR_SIGNAL = 85, + + /// Used for special AVR rtlib functions which have an "optimized" + /// convention to preserve registers. + AVR_BUILTIN = 86, + + /// Used for Mesa vertex shaders, or AMDPAL last shader stage before + /// rasterization (vertex shader if tessellation and geometry are not in + /// use, or otherwise copy shader if one is needed). + AMDGPU_VS = 87, + + /// Used for Mesa/AMDPAL geometry shaders. + AMDGPU_GS = 88, + + /// Used for Mesa/AMDPAL pixel shaders. + AMDGPU_PS = 89, + + /// Used for Mesa/AMDPAL compute shaders. + AMDGPU_CS = 90, + + /// Used for AMDGPU code object kernels. + AMDGPU_KERNEL = 91, + + /// Register calling convention used for parameters transfer optimization + X86_RegCall = 92, + + /// Used for Mesa/AMDPAL hull shaders (= tessellation control shaders). + AMDGPU_HS = 93, + + /// Used for special MSP430 rtlib functions which have an "optimized" + /// convention using additional registers. + MSP430_BUILTIN = 94, + + /// Used for AMDPAL vertex shader if tessellation is in use. + AMDGPU_LS = 95, + + /// Used for AMDPAL shader stage before geometry shader if geometry is in + /// use. So either the domain (= tessellation evaluation) shader if + /// tessellation is in use, or otherwise the vertex shader. + AMDGPU_ES = 96, + + /// Used between AArch64 Advanced SIMD functions + AArch64_VectorCall = 97, + + /// Used between AArch64 SVE functions + AArch64_SVE_VectorCall = 98, + + /// For emscripten __invoke_* functions. The first argument is required to + /// be the function ptr being indirectly called. The remainder matches the + /// regular calling convention. + WASM_EmscriptenInvoke = 99, + + /// Used for AMD graphics targets. + AMDGPU_Gfx = 100, + + /// Used for M68k interrupt routines. + M68k_INTR = 101, + + /// Preserve X0-X13, X19-X29, SP, Z0-Z31, P0-P15. + AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0 = 102, + + /// Preserve X2-X15, X19-X29, SP, Z0-Z31, P0-P15. + AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2 = 103, + + /// The highest possible ID. Must be some 2^k - 1. + MaxID = 1023, + }; + }; + + pub const Int = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + }; + + pub const GlobalVariable = opaque { + pub const setInitializer = bindings.NativityLLVMGlobalVariableSetInitializer; + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + }; + + pub const PointerNull = opaque { + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + }; + + pub const Undefined = opaque { + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Poison = opaque { + fn toConstant(this: *@This()) *Constant { + return @ptrCast(this); + } + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + + const toInt = bindings.NativityLLVMConstantToInt; + }; + + pub const InlineAssembly = opaque { + pub const Dialect = enum(c_uint) { + @"at&t", + intel, + }; + const get = bindings.NativityLLVMGetInlineAssembly; + fn toValue(this: *@This()) *LLVM.Value { + return @ptrCast(this); + } + }; + + pub const Error = error{ + constant_struct, + constant_int, + constant_array, + inline_assembly, + global_variable, + intrinsic, + }; + }; +}; diff --git a/bootstrap/library.zig b/bootstrap/library.zig index 68b8fb6..1739a2a 100644 --- a/bootstrap/library.zig +++ b/bootstrap/library.zig @@ -155,17 +155,19 @@ const pinned_array_page_size = 2 * 1024 * 1024; const pinned_array_max_size = std.math.maxInt(u32) - pinned_array_page_size; const pinned_array_default_granularity = pinned_array_page_size; +const small_granularity = 0x1000; +const large_granularity = 2 * 1024 * 1024; // This must be used with big arrays, which are not resizeable (can't be cleared) pub fn PinnedArray(comptime T: type) type { - return PinnedArrayAdvanced(T, null); + return PinnedArrayAdvanced(T, null, small_granularity); } // This must be used with big arrays, which are not resizeable (can't be cleared) -pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type) type { +pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type, comptime granularity: comptime_int) type { return struct { - pointer: [*]T = @constCast((&[_]T{}).ptr), + pointer: [*]T = undefined, length: u32 = 0, - granularity: u32 = 0, + committed: u32 = 0, pub const Index = if (MaybeIndex) |I| getIndexForType(T, I) else enum(u32) { null = 0xffff_ffff, @@ -193,38 +195,36 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type) type { return array.get_unchecked(i); } - pub fn get_index(array: *Array, item: *T) Index { + pub fn get_index(array: *Array, item: *T) u32 { const many_item: [*]T = @ptrCast(item); - const result = @intFromPtr(many_item) - @intFromPtr(array.pointer); + const result: u32 = @intCast(@intFromPtr(many_item) - @intFromPtr(array.pointer)); assert(result < pinned_array_max_size); - return @enumFromInt(@divExact(result, @sizeOf(T))); + return @divExact(result, @sizeOf(T)); } - pub fn init(granularity: u32) !Array { - assert(granularity & 0xfff == 0); - const raw_ptr = try reserve(pinned_array_max_size); - try commit(raw_ptr, granularity); - return Array{ - .pointer = @alignCast(@ptrCast(raw_ptr)), - .length = 0, - .granularity = granularity, - }; - } - - pub fn init_with_default_granularity() !Array { - return try Array.init(pinned_array_default_granularity); + pub fn get_typed_index(array: *Array, item: *T) Index { + return @enumFromInt(array.get_index(item)); } pub fn ensure_capacity(array: *Array, additional: u32) void { + if (array.committed == 0) { + assert(array.length == 0); + array.pointer = @alignCast(@ptrCast(reserve(pinned_array_max_size) catch unreachable)); + } + const length = array.length; const size = length * @sizeOf(T); - const granularity_aligned_size = align_forward(size, array.granularity); + const granularity_aligned_size = align_forward(size, granularity); const new_size = size + additional * @sizeOf(T); + if (granularity_aligned_size < new_size) { assert((length + additional) * @sizeOf(T) <= pinned_array_max_size); - const new_granularity_aligned_size = align_forward(new_size, array.granularity); - const ptr: [*]u8 = @ptrCast(array.pointer); - commit(ptr + granularity_aligned_size, new_granularity_aligned_size - granularity_aligned_size) catch unreachable; + const new_granularity_aligned_size = align_forward(new_size, granularity); + const pointer: [*]u8 = @ptrCast(array.pointer); + const commit_pointer = pointer + granularity_aligned_size; + const commit_size = new_granularity_aligned_size - granularity_aligned_size; + commit(commit_pointer, commit_size) catch unreachable; + array.committed += @intCast(@divExact(commit_size, granularity)); } } @@ -233,30 +233,46 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type) type { return array.append_with_capacity(item); } - pub fn append_index(array: *Array, item: T) Index { + pub fn append_index(array: *Array, item: T) u32 { return array.get_index(array.append(item)); } + pub fn append_typed_index(array: *Array, item: T) Index { + return array.get_typed_index(array.append(item)); + } + pub fn append_slice(array: *Array, items: []const T) void { array.ensure_capacity(@intCast(items.len)); array.append_slice_with_capacity(items); } - pub fn append_with_capacity(array: *Array, item: T) *T { + pub fn add_one_with_capacity(array: *Array) *T { const index = array.length; assert(index * @sizeOf(T) < pinned_array_max_size); array.length += 1; const ptr = &array.pointer[index]; + return ptr; + } + + pub fn add_one(array: *Array) *T{ + array.ensure_capacity(1); + return array.add_one_with_capacity(); + } + + pub fn append_with_capacity(array: *Array, item: T) *T { + const ptr = array.add_one_with_capacity(); ptr.* = item; return ptr; } pub fn append_slice_with_capacity(array: *Array, items: []const T) void { - const index = array.length; - const count: u32 = @intCast(items.len); - assert((index + count - 1) * @sizeOf(T) < pinned_array_max_size); - array.length += count; - @memcpy(array.pointer[index..][0..count], items); + if (items.len > 0) { + const index = array.length; + const count: u32 = @intCast(items.len); + assert((index + count - 1) * @sizeOf(T) < pinned_array_max_size); + array.length += count; + @memcpy(array.pointer[index..][0..count], items); + } } pub fn insert(array: *@This(), index: u32, item: T) void { @@ -268,6 +284,14 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type) type { copy_backwards(T, dst, src); array.slice()[index] = item; } + + pub fn in_range(array: *@This(), item: *T) bool { + if (array.committed == 0) return false; + if (@intFromPtr(item) < @intFromPtr(array.pointer)) return false; + const top = @intFromPtr(array.pointer) + array.committed * granularity; + if (@intFromPtr(item) >= top) return false; + return true; + } }; } @@ -385,31 +409,19 @@ const pinned_hash_map_max_size = std.math.maxInt(u32) - pinned_hash_map_page_siz const pinned_hash_map_default_granularity = pinned_hash_map_page_size; pub fn PinnedHashMap(comptime K: type, comptime V: type) type { + return PinnedHashMapAdvanced(K, V, small_granularity); +} + +pub fn PinnedHashMapAdvanced(comptime K: type, comptime V: type, comptime granularity: comptime_int) type { return struct { - key_pointer: [*]K, - value_pointer: [*]V, - length: u32, - granularity: u32, - committed: u32, + key_pointer: [*]K = undefined, + value_pointer: [*]V = undefined, + length: u64 = 0, + committed_key: u32 = 0, + committed_value: u32 = 0, const Map = @This(); - pub fn init(granularity: u32) !Map { - assert(granularity & 0xfff == 0); - const key_raw_pointer = try reserve(pinned_hash_map_max_size); - try commit(key_raw_pointer, granularity); - const value_raw_pointer = try reserve(pinned_hash_map_max_size); - try commit(value_raw_pointer, granularity); - - return Map{ - .key_pointer = @alignCast(@ptrCast(key_raw_pointer)), - .value_pointer = @alignCast(@ptrCast(value_raw_pointer)), - .length = 0, - .granularity = granularity, - .committed = 1, - }; - } - pub fn get_pointer(map: *Map, key: K) ?*V { for (map.keys(), 0..) |k, i| { const is_equal = switch (@typeInfo(K)) { @@ -437,7 +449,7 @@ pub fn PinnedHashMap(comptime K: type, comptime V: type) type { } } - pub fn put(map: *@This(), key: K, value: V) !void { + pub fn put(map: *@This(), key: K, value: V) void { if (map.get_pointer(key)) |value_pointer| { value_pointer.* = value; } else { @@ -447,45 +459,57 @@ pub fn PinnedHashMap(comptime K: type, comptime V: type) type { } } - pub fn put_no_clobber(map: *@This(), key: K, value: V) !void { + pub fn put_no_clobber(map: *@This(), key: K, value: V) void { assert(map.get_pointer(key) == null); const len = map.length; map.ensure_capacity(len + 1); map.put_at_with_capacity(len, key, value); } - fn put_at_with_capacity(map: *@This(), index: u32, key: K, value: V) void { + fn put_at_with_capacity(map: *@This(), index: u64, key: K, value: V) void { map.length += 1; assert(index < map.length); map.key_pointer[index] = key; map.value_pointer[index] = value; } - fn ensure_capacity(map: *Map, additional: u32) void { + fn ensure_capacity(map: *Map, additional: u64) void { + if (map.committed_key == 0) { + map.key_pointer = @alignCast(@ptrCast(reserve(pinned_hash_map_max_size) catch unreachable)); + map.value_pointer = @alignCast(@ptrCast(reserve(pinned_hash_map_max_size) catch unreachable)); + } + const length = map.length; assert((length + additional) * @sizeOf(K) <= pinned_array_max_size); { const key_size = length * @sizeOf(K); - const key_granularity_aligned_size = align_forward(key_size, map.granularity); + const key_granularity_aligned_size = align_forward(key_size, granularity); const key_new_size = key_size + additional * @sizeOf(K); if (key_granularity_aligned_size < key_new_size) { - const new_key_granularity_aligned_size = align_forward(key_new_size, map.granularity); + const new_key_granularity_aligned_size = align_forward(key_new_size, granularity); const key_pointer: [*]u8 = @ptrCast(map.key_pointer); - commit(key_pointer + key_granularity_aligned_size, new_key_granularity_aligned_size - key_granularity_aligned_size) catch unreachable; + const commit_pointer = key_pointer + key_granularity_aligned_size; + const commit_size = new_key_granularity_aligned_size - key_granularity_aligned_size; + commit(commit_pointer, commit_size) catch unreachable; + map.committed_key += @intCast(@divExact(commit_size, granularity)); } } { const value_size = length * @sizeOf(V); - const value_granularity_aligned_size = align_forward(value_size, map.granularity); + const value_granularity_aligned_size = align_forward(value_size, granularity); const value_new_size = value_size + additional * @sizeOf(K); if (value_granularity_aligned_size < value_new_size) { - const new_value_granularity_aligned_size = align_forward(value_new_size, map.granularity); + const new_value_granularity_aligned_size = align_forward(value_new_size, granularity); const value_pointer: [*]u8 = @ptrCast(map.value_pointer); commit(value_pointer + value_granularity_aligned_size, new_value_granularity_aligned_size - value_granularity_aligned_size) catch unreachable; + const commit_pointer = value_pointer + value_granularity_aligned_size; + const commit_size = new_value_granularity_aligned_size - value_granularity_aligned_size; + commit(commit_pointer, commit_size) catch unreachable; + map.committed_value += @intCast(@divExact(commit_size, granularity)); } } } @@ -737,3 +761,40 @@ pub fn exit_with_error() noreturn { @breakpoint(); std.posix.exit(1); } + +pub fn read_file(arena: *Arena, directory: std.fs.Dir, file_relative_path: []const u8) []const u8 { + const source_file = directory.openFile(file_relative_path, .{}) catch |err| { + const stdout = std.io.getStdOut(); + stdout.writeAll("Can't find file ") catch {}; + stdout.writeAll(file_relative_path) catch {}; + // stdout.writeAll(" in directory ") catch {}; + // stdout.writeAll(file.package.directory.path) catch {}; + stdout.writeAll(" for error ") catch {}; + stdout.writeAll(@errorName(err)) catch {}; + @panic("Unrecoverable error"); + }; + + const file_size = source_file.getEndPos() catch unreachable; + var file_buffer = arena.new_array(u8, file_size) catch unreachable; + + const read_byte_count = source_file.readAll(file_buffer) catch unreachable; + assert(read_byte_count == file_size); + source_file.close(); + + //TODO: adjust file maximum size + return file_buffer[0..read_byte_count]; +} + + +pub fn self_exe_path(arena: *Arena) ![]const u8 { + var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + return try arena.duplicate_bytes(try std.fs.selfExePath(&buffer)); +} + +pub fn realpath(arena: *Arena, dir: std.fs.Dir, relative_path: []const u8) ![]const u8 { + var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const stack_realpath = try dir.realpath(relative_path, &buffer); + const heap_realpath = try arena.new_array(u8, stack_realpath.len); + @memcpy(heap_realpath, stack_realpath); + return heap_realpath; +} diff --git a/bootstrap/main.zig b/bootstrap/main.zig index 197d33e..92603ed 100644 --- a/bootstrap/main.zig +++ b/bootstrap/main.zig @@ -9,6 +9,7 @@ const byte_equal = library.byte_equal; const configuration = @import("configuration"); const editor = @import("editor.zig"); +const compiler = @import("compiler.zig"); const env_detecting_libc_paths = "NATIVITY_IS_DETECTING_LIBC_PATHS"; @@ -25,52 +26,55 @@ pub fn main() !void { if (configuration.editor) { editor.main(); } else { - var arg_iterator = std.process.ArgIterator.init(); - var buffer = library.BoundedArray([]const u8, 512){}; - while (arg_iterator.next()) |argument| { - buffer.appendAssumeCapacity(argument); - } - const arguments = buffer.slice(); - const context = try Compilation.createContext(); - - if (arguments.len <= 1) { - return error.InvalidInput; - } - - if (std.process.can_execv and std.posix.getenvZ(env_detecting_libc_paths) != null) { - todo(); - } - - const command = arguments[1]; - const command_arguments = arguments[2..]; - - if (byte_equal(command, "build")) { - try Compilation.compileBuildExecutable(context, command_arguments); - } else if (byte_equal(command, "clang") or byte_equal(command, "-cc1") or byte_equal(command, "-cc1as")) { - const exit_code = try Compilation.clangMain(context.arena, arguments); - std.process.exit(exit_code); - } else if (byte_equal(command, "cc")) { - try Compilation.compileCSourceFile(context, command_arguments, .c); - } else if (byte_equal(command, "c++")) { - try Compilation.compileCSourceFile(context, command_arguments, .cpp); - } else if (byte_equal(command, "exe")) { - try Compilation.buildExecutable(context, command_arguments, .{ - .is_test = false, - }); - } else if (byte_equal(command, "lib")) { - todo(); - } else if (byte_equal(command, "obj")) { - todo(); - } else if (byte_equal(command, "test")) { - try Compilation.buildExecutable(context, command_arguments, .{ - .is_test = true, - }); - } else { - todo(); - } + compiler.make(); + // var arg_iterator = std.process.ArgIterator.init(); + // var buffer = library.BoundedArray([]const u8, 512){}; + // while (arg_iterator.next()) |argument| { + // buffer.appendAssumeCapacity(argument); + // } + // const arguments = buffer.slice(); + // const context = try Compilation.createContext(); + // + // if (arguments.len <= 1) { + // return error.InvalidInput; + // } + // + // if (std.process.can_execv and std.posix.getenvZ(env_detecting_libc_paths) != null) { + // todo(); + // } + // + // const command = arguments[1]; + // const command_arguments = arguments[2..]; + // + // if (byte_equal(command, "build")) { + // try Compilation.compileBuildExecutable(context, command_arguments); + // } else if (byte_equal(command, "clang") or byte_equal(command, "-cc1") or byte_equal(command, "-cc1as")) { + // const exit_code = try Compilation.clangMain(context.arena, arguments); + // std.process.exit(exit_code); + // } else if (byte_equal(command, "cc")) { + // try Compilation.compileCSourceFile(context, command_arguments, .c); + // } else if (byte_equal(command, "c++")) { + // try Compilation.compileCSourceFile(context, command_arguments, .cpp); + // } else if (byte_equal(command, "exe")) { + // try Compilation.buildExecutable(context, command_arguments, .{ + // .is_test = false, + // }); + // } else if (byte_equal(command, "lib")) { + // todo(); + // } else if (byte_equal(command, "obj")) { + // todo(); + // } else if (byte_equal(command, "test")) { + // try Compilation.buildExecutable(context, command_arguments, .{ + // .is_test = true, + // }); + // } else { + // todo(); + // } } } pub const std_options = std.Options{ .enable_segfault_handler = false, }; + + diff --git a/build.zig b/build.zig index 7a486ae..c6c5500 100644 --- a/build.zig +++ b/build.zig @@ -26,7 +26,8 @@ pub fn build(b: *std.Build) !void { const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci; const native_target = b.resolveTargetQuery(.{}); const optimization = b.standardOptimizeOption(.{}); - const use_editor = b.option(bool, "editor", "Use the GUI editor to play around the programming language") orelse !is_ci; + const enable_editor = false; + const use_editor = b.option(bool, "editor", "Use the GUI editor to play around the programming language") orelse (!is_ci and enable_editor); const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false; const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse switch (@import("builtin").os.tag) { else => use_debug, @@ -40,7 +41,7 @@ pub fn build(b: *std.Build) !void { const fetcher = b.addExecutable(.{ .name = "llvm_fetcher", - .root_source_file = .{ .path = "build/fetcher.zig" }, + .root_source_file = b.path("build/fetcher.zig"), .target = native_target, .optimize = .Debug, .single_threaded = true, @@ -82,18 +83,18 @@ pub fn build(b: *std.Build) !void { const compiler = b.addExecutable(.{ .name = "nat", - .root_source_file = .{ .path = "bootstrap/main.zig" }, + .root_source_file = b.path("bootstrap/main.zig"), .target = target, .optimize = optimization, }); const cpp_files = .{ "src/llvm/llvm.cpp", - "src/llvm/lld.cpp", - "src/llvm/clang_main.cpp", - "src/llvm/clang_cc1.cpp", - "src/llvm/clang_cc1as.cpp", - "src/llvm/ar.cpp", + // "src/llvm/lld.cpp", + // "src/llvm/clang_main.cpp", + // "src/llvm/clang_cc1.cpp", + // "src/llvm/clang_cc1as.cpp", + // "src/llvm/ar.cpp", }; compiler.addCSourceFiles(.{ @@ -408,8 +409,8 @@ pub fn build(b: *std.Build) !void { break :blk llvm_directory.items; } else { break :blk switch (use_debug) { - true => "../llvm-17-static-debug", - false => "../llvm-17-static-release", + true => "../zig-bootstrap/out/x86_64-linux-musl-native-debug-static", + false => "../zig-bootstrap/out/x86_64-linux-musl-native-release-static", }; } }; @@ -422,16 +423,16 @@ pub fn build(b: *std.Build) !void { compiler.addObjectFile(std.Build.path(b, try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library }))); } } else { - compiler.linkSystemLibrary("LLVM-17"); - compiler.linkSystemLibrary("clang-cpp"); - compiler.linkSystemLibrary("lldCommon"); - compiler.linkSystemLibrary("lldCOFF"); - compiler.linkSystemLibrary("lldELF"); - compiler.linkSystemLibrary("lldMachO"); - compiler.linkSystemLibrary("lldWasm"); - compiler.linkSystemLibrary("unwind"); - compiler.linkSystemLibrary(if (is_ci) "z" else "zlib"); - compiler.linkSystemLibrary("zstd"); + compiler.linkSystemLibrary("LLVM"); + // compiler.linkSystemLibrary("clang-cpp"); + // compiler.linkSystemLibrary("lldCommon"); + // compiler.linkSystemLibrary("lldCOFF"); + // compiler.linkSystemLibrary("lldELF"); + // compiler.linkSystemLibrary("lldMachO"); + // compiler.linkSystemLibrary("lldWasm"); + // compiler.linkSystemLibrary("unwind"); + // compiler.linkSystemLibrary(if (is_ci) "z" else "zlib"); + // compiler.linkSystemLibrary("zstd"); switch (target.result.os.tag) { .linux => { @@ -475,11 +476,11 @@ pub fn build(b: *std.Build) !void { const cxx_include_base = try std.mem.concat(b.allocator, u8, &.{ "/usr/include/c++/", cxx_version }); const cxx_include_arch = try std.mem.concat(b.allocator, u8, &.{ cxx_include_base, "/" ++ @tagName(@import("builtin").cpu.arch) ++ "-pc-linux-gnu" }); compiler.addObjectFile(.{ .cwd_relative = "/usr/lib64/libstdc++.so.6" }); - compiler.addIncludePath(.{ .cwd_relative = "/usr/lib64/llvm17/include/" }); + compiler.addIncludePath(.{ .cwd_relative = "../../local/llvm18-debug/include" }); compiler.addIncludePath(.{ .cwd_relative = "/usr/include" }); compiler.addIncludePath(.{ .cwd_relative = cxx_include_base }); compiler.addIncludePath(.{ .cwd_relative = cxx_include_arch }); - compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib64/llvm17/lib" }); + compiler.addLibraryPath(.{ .cwd_relative = "../../local/llvm18-debug/lib" }); compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib64" }); } }, @@ -557,6 +558,7 @@ pub fn build(b: *std.Build) !void { const debug_command = switch (os) { .linux => blk: { const result = b.addSystemCommand(&.{"gf2"}); + result.addArgs(&.{ "-ex", "set debuginfod enabled off" }); result.addArgs(&.{ "-ex", "set disassembly-flavor intel" }); result.addArg("-ex=r"); result.addArgs(&.{ "-ex", "up" }); @@ -581,7 +583,7 @@ pub fn build(b: *std.Build) !void { const test_runner = b.addExecutable(.{ .name = "test_runner", - .root_source_file = .{ .path = "build/test_runner.zig" }, + .root_source_file = b.path("build/test_runner.zig"), .target = native_target, .optimize = optimization, .single_threaded = true, @@ -609,3 +611,5 @@ pub fn build(b: *std.Build) !void { const test_all = b.step("test_all", "Test all"); test_all.dependOn(&test_command.step); } + + diff --git a/newlib/std/std.nat b/newlib/std/std.nat new file mode 100644 index 0000000..1b99bdc --- /dev/null +++ b/newlib/std/std.nat @@ -0,0 +1,4 @@ +fn[extern] exit(exit_code: s32) noreturn; +fn my_exit(exit_code: s32) noreturn { + exit(exit_code); +} diff --git a/retest/standalone/first/file.nat b/retest/standalone/first/file.nat new file mode 100644 index 0000000..295d779 --- /dev/null +++ b/retest/standalone/first/file.nat @@ -0,0 +1,4 @@ +fn foo() s32 +{ + return 0; +} diff --git a/retest/standalone/first/main.nat b/retest/standalone/first/main.nat new file mode 100644 index 0000000..45970a5 --- /dev/null +++ b/retest/standalone/first/main.nat @@ -0,0 +1,6 @@ +import "file.nat"; + +fn [cc(.c)] main [export]() s32 +{ + return file.foo(); +} diff --git a/src/llvm/llvm.cpp b/src/llvm/llvm.cpp index 183280d..d11ee1e 100644 --- a/src/llvm/llvm.cpp +++ b/src/llvm/llvm.cpp @@ -1,11 +1,16 @@ #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" +#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" + +#include "llvm/Linker/Linker.h" + +#include "llvm/Passes/PassBuilder.h" + #include "llvm/MC/TargetRegistry.h" #include "llvm/TargetParser/Host.h" @@ -17,6 +22,8 @@ using namespace llvm; +using llvm::orc::ThreadSafeContext; +using llvm::orc::ThreadSafeModule; extern "C" LLVMContext* NativityLLVMCreateContext() { @@ -280,6 +287,13 @@ extern "C" StructType* NativityLLVMGetStructType(LLVMContext& context, Type** ty auto* struct_type = StructType::get(context, types, is_packed); return struct_type; } + +extern "C" LLVMContext* NativityLLVMTypeGetContext(Type& type) +{ + auto& context = type.getContext(); + return &context; +} + extern "C" Function* NativityLLVMModuleGetFunction(Module& module, const char* name_ptr, size_t name_len) { auto name = StringRef(name_ptr, name_len); @@ -737,15 +751,14 @@ extern "C" bool NativityLLVMVerifyModule(const Module& module, const char** mess return !result; } -extern "C" const char* NativityLLVMFunctionToString(const Function& function, size_t* len) +extern "C" void NativityLLVMFunctionToString(const Function& function, const char** ptr, size_t* len) { std::string buf; raw_string_ostream os(buf); function.print(os); os.flush(); *len = buf.size(); - auto* result = strdup(buf.c_str()); - return result; + *ptr = strdup(buf.c_str()); } extern "C" Type* NativityLLVMAllocatGetAllocatedType(AllocaInst& alloca) @@ -829,26 +842,24 @@ extern "C" Type* NativityLLVMArrayTypeGetElementType(ArrayType* array_type) return element_type; } -extern "C" const char* NativityLLVMModuleToString(const Module& module, size_t* len) +extern "C" void NativityLLVMModuleToString(const Module& module, const char** ptr, size_t* len) { std::string buf; raw_string_ostream os(buf); module.print(os, nullptr); os.flush(); *len = buf.size(); - auto* result = strdup(buf.c_str()); - return result; + *ptr = strdup(buf.c_str()); } -extern "C" const char* NativityLLVMValueToString(const Value& value, size_t* len) +extern "C" void NativityLLVMValueToString(const Value& value, const char** ptr, size_t* len) { std::string buf; raw_string_ostream os(buf); value.print(os, true); os.flush(); *len = buf.size(); - auto* result = strdup(buf.c_str()); - return result; + *ptr = strdup(buf.c_str()); } extern "C" BasicBlock* NativityLLVMBuilderGetInsertBlock(IRBuilder<>& builder) @@ -910,19 +921,20 @@ extern "C" const Target* NativityLLVMGetTarget(const char* target_triple_ptr, si return target; } -extern "C" TargetMachine* NativityLLVMTargetCreateTargetMachine(Target& target, const char* target_triple_ptr, size_t target_triple_len, const char* cpu_ptr, size_t cpu_len, const char* features_ptr, size_t features_len, Reloc::Model relocation_model, CodeModel::Model maybe_code_model, bool is_code_model_present, CodeGenOpt::Level optimization_level, bool jit) -{ - auto target_triple = StringRef(target_triple_ptr, target_triple_len); - auto cpu = StringRef(cpu_ptr, cpu_len); - auto features = StringRef(features_ptr, features_len); - TargetOptions target_options; - std::optional code_model = std::nullopt; - if (is_code_model_present) { - code_model = maybe_code_model; - } - TargetMachine* target_machine = target.createTargetMachine(target_triple, cpu, features, target_options, relocation_model, code_model, optimization_level, jit); - return target_machine; -} +// TODO: +// extern "C" TargetMachine* NativityLLVMTargetCreateTargetMachine(Target& target, const char* target_triple_ptr, size_t target_triple_len, const char* cpu_ptr, size_t cpu_len, const char* features_ptr, size_t features_len, Reloc::Model relocation_model, CodeModel::Model maybe_code_model, bool is_code_model_present, CodeGenOpt::Level optimization_level, bool jit) +// { +// auto target_triple = StringRef(target_triple_ptr, target_triple_len); +// auto cpu = StringRef(cpu_ptr, cpu_len); +// auto features = StringRef(features_ptr, features_len); +// TargetOptions target_options; +// std::optional code_model = std::nullopt; +// if (is_code_model_present) { +// code_model = maybe_code_model; +// } +// TargetMachine* target_machine = target.createTargetMachine(target_triple, cpu, features, target_options, relocation_model, code_model, optimization_level, jit); +// return target_machine; +// } extern "C" void NativityLLVMModuleSetTargetMachineDataLayout(Module& module, TargetMachine& target_machine) { @@ -1065,6 +1077,13 @@ extern "C" CallInst* NativityLLVMBuilderCreateMemcpy(IRBuilder<>& builder, Value return memcpy; } +extern "C" bool NativityLLVMLinkModules(Module& destination, Module* source) +{ + auto src = std::unique_ptr(source); + bool result = Linker::linkModules(destination, std::move(src)); + // Invert the condition because LLVM boolean concept is lame + return !result; +} extern "C" void NativityLLVMTypeAssertEqual(Type* a, Type* b) { assert(a == b);