From 1c220decf8b4d8cefed74a115c30af997df5f234 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 6 May 2025 08:34:42 -0600 Subject: [PATCH] wip --- generate.sh | 11 +- src/compiler.h | 270 +++++++++- src/emitter.cpp | 1293 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.h | 1 + src/llvm.cpp | 875 ++++++++++++++------------------ src/llvm.h | 410 ++++++++++++++- src/parser.cpp | 4 + 7 files changed, 2353 insertions(+), 511 deletions(-) diff --git a/generate.sh b/generate.sh index 9bba737..e0ca562 100755 --- a/generate.sh +++ b/generate.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash set -eu -rm -rf build -mkdir build -cd build -cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=MOLD -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release -DCMAKE_COLOR_DIAGNOSTICS=ON +CMAKE_BUILD_TYPE=Debug +LLVM_CMAKE_BUILD_TYPE=Release +BUILD_DIR=build +rm -rf $BUILD_DIR +mkdir $BUILD_DIR +cd $BUILD_DIR +cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=MOLD -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-$LLVM_CMAKE_BUILD_TYPE -DCMAKE_COLOR_DIAGNOSTICS=ON cd .. diff --git a/src/compiler.h b/src/compiler.h index a4dc6f2..819679b 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,7 +1,7 @@ #pragma once #include - +#include #define report_error() trap_raw() enum class Command @@ -38,6 +38,23 @@ fn String build_mode_to_string(BuildMode build_mode) } } +fn bool build_mode_is_optimized(BuildMode build_mode) +{ + switch (build_mode) + { + case BuildMode::debug_none: + case BuildMode::debug: + return false; + case BuildMode::soft_optimize: + case BuildMode::optimize_for_speed: + case BuildMode::optimize_for_size: + case BuildMode::aggressively_optimize_for_speed: + case BuildMode::aggressively_optimize_for_size: + return true; + case BuildMode::count: unreachable(); + } +} + enum class ValueKind { right, @@ -65,6 +82,165 @@ struct Argument; struct Scope; struct MacroDeclaration; +struct DirectAttributes +{ + u32 offset; + u32 alignment; +}; + +struct IndirectAttributes +{ + u32 alignment; + u32 address_space; +}; + +enum class AbiKind : u8 +{ + ignore, + direct, + extend, + indirect, + indirect_aliased, + expand, + coerce_and_expand, + in_alloca, +}; + +struct AbiFlags +{ + AbiKind kind; + bool padding_in_reg; + bool in_alloca_sret; + bool in_alloca_indirect; + bool indirect_by_value; + bool indirect_realign; + bool sret_after_this; + bool in_reg; + bool can_be_flattened; + bool sign_extension; +}; + +struct AbiInformation +{ + Type* semantic_type; + Type* coerce_to_type; + union + { + Type* type; + Type* unpadded_coerce_and_expand_type; + } padding; + u16 padding_argument_index; + union + { + DirectAttributes direct; + IndirectAttributes indirect; + u32 alloca_field_index; + } attributes; + AbiFlags flags; + u16 abi_start; + u16 abi_count; + + inline void set_sret_after_this(bool sret_after_this) + { + assert(flags.kind == AbiKind::indirect); + flags.sret_after_this = sret_after_this; + } + + inline void set_indirect_realign(bool realign) + { + assert(flags.kind == AbiKind::indirect); + flags.indirect_realign = realign; + } + + inline void set_indirect_by_value(bool by_value) + { + assert(flags.kind == AbiKind::indirect); + flags.indirect_by_value = by_value; + } + + inline void set_indirect_align(u32 alignment) + { + assert(flags.kind == AbiKind::indirect || flags.kind == AbiKind::indirect_aliased); + attributes.indirect.alignment = alignment; + } + + inline bool can_have_coerce_to_type() + { + switch (flags.kind) + { + case AbiKind::direct: + case AbiKind::extend: + case AbiKind::coerce_and_expand: + return true; + default: + return false; + } + } + + inline void set_coerce_to_type(Type* coerce_to_type) + { + assert(can_have_coerce_to_type()); + this->coerce_to_type = coerce_to_type; + } + + inline Type* get_coerce_to_type() + { + assert(can_have_coerce_to_type()); + return coerce_to_type; + } + + inline void set_padding_type(Type* padding_type) + { + assert(can_have_coerce_to_type()); + padding = { + .type = padding_type, + }; + } + + inline bool can_have_padding_type() + { + switch (flags.kind) + { + case AbiKind::direct: + case AbiKind::extend: + case AbiKind::indirect: + case AbiKind::indirect_aliased: + case AbiKind::expand: + return true; + default: + return false; + } + } + + inline Type* get_padding_type() + { + return can_have_padding_type() ? padding.type : 0; + } + + inline void set_direct_offset(u32 offset) + { + assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend); + attributes.direct.offset = offset; + } + + inline void set_direct_alignment(u32 alignment) + { + assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend); + attributes.direct.alignment = alignment; + } + + inline void set_can_be_flattened(bool can_be_flattened) + { + assert(flags.kind == AbiKind::direct); + flags.can_be_flattened = can_be_flattened; + } + + inline bool get_can_be_flattened() + { + return flags.can_be_flattened; + } +}; + struct Target { CPUArchitecture cpu; @@ -87,6 +263,24 @@ enum class CallingConvention count, }; +enum class ResolvedCallingConvention +{ + system_v, + win64, + count, +}; + +fn ResolvedCallingConvention resolve_calling_convention(CallingConvention cc) +{ + switch (cc) + { + case CallingConvention::c: + // TODO: + return ResolvedCallingConvention::system_v; + case CallingConvention::count: unreachable(); + } +} + enum class InlineBehavior { normal, @@ -124,12 +318,29 @@ struct TypeInteger bool is_signed; }; +struct AbiRegisterCountSystemV +{ + u32 gpr; + u32 sse; +}; + +union AbiRegisterCount +{ + AbiRegisterCountSystemV system_v; +}; + struct TypeFunction { Type* semantic_return_type; Slice semantic_argument_types; CallingConvention calling_convention; bool is_variable_arguments; + // ABI + Slice abi_argument_types; + Type* abi_return_type; + AbiRegisterCount available_registers; + Slice argument_abis; + AbiInformation return_abi; }; struct TypePointer @@ -221,6 +432,13 @@ struct TypeUnion u32 biggest_field; }; +struct LLVMType +{ + LLVMTypeRef abi; + LLVMTypeRef memory; + LLVMMetadataRef debug; +}; + struct Type { union @@ -238,6 +456,7 @@ struct Type TypeId id; String name; Type* next; + LLVMType llvm; }; fn u32 align_bit_count(u32 bit_count) @@ -340,6 +559,7 @@ struct Scope u32 line; u32 column; ScopeKind kind; + LLVMMetadataRef llvm; }; enum class StatementId @@ -487,12 +707,19 @@ struct ValueConstantInteger bool is_signed; }; +struct FunctionLLVM +{ + LLVMBasicBlockRef return_block; + LLVMValueRef return_alloca; +}; + struct ValueFunction { Slice arguments; Scope scope; Block* block; FunctionAttributes attributes; + FunctionLLVM llvm; }; enum class UnaryId @@ -694,6 +921,7 @@ struct Value Type* type; ValueId id; ValueKind kind; + LLVMValueRef llvm; bool is_constant() { @@ -742,6 +970,45 @@ struct Argument u32 index; }; +struct LLVMIntrinsicId +{ + u32 n; +}; + +enum class IntrinsicIndex +{ + trap, + va_start, + va_end, + va_copy, + count, +}; + +global_variable String intrinsic_names[] = { + string_literal("llvm.trap"), + string_literal("llvm.va_start"), + string_literal("llvm.va_end"), + string_literal("llvm.va_copy"), +}; + +static_assert(array_length(intrinsic_names) == (u64)IntrinsicIndex::count); + +struct ModuleLLVM +{ + LLVMContextRef context; + LLVMModuleRef module; + LLVMBuilderRef builder; + LLVMDIBuilderRef di_builder; + LLVMMetadataRef file; + LLVMMetadataRef compile_unit; + LLVMTypeRef pointer_type; + LLVMTypeRef void_type; + LLVMIntrinsicId intrinsic_table[(u64)IntrinsicIndex::count]; + LLVMValueRef memcmp; + LLVMMetadataRef inlined_at; + u32 debug_tag; +}; + struct Module { Arena* arena; @@ -768,6 +1035,7 @@ struct Module MacroDeclaration* current_macro_declaration; MacroInstantiation* current_macro_instantiation; + ModuleLLVM llvm; Scope scope; String name; diff --git a/src/emitter.cpp b/src/emitter.cpp index 105e6d8..b67a90e 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -1,5 +1,1298 @@ #include +#include + +fn void dump_module(Module* module) +{ + print(llvm_module_to_string(module->llvm.module)); +} + +fn bool type_is_signed(Type* type) +{ + switch (type->id) + { + case TypeId::integer: + return type->integer.is_signed; + default: unreachable(); + } +} + +enum class EvaluationKind +{ + scalar, + aggregate, + complex, +}; + +enum class TypeKind +{ + abi, + memory, +}; + +fn Type* resolve_alias(Module* module, Type* type) +{ + Type* result_type = 0; + switch (type->id) + { + case TypeId::integer: + { + result_type = type; + } break; + case TypeId::pointer: + { + auto* element_type = type->pointer.element_type; + auto* resolved_element_type = resolve_alias(module, element_type); + result_type = get_pointer_type(module, resolved_element_type); + } break; + default: unreachable(); + } + + assert(result_type); + return result_type; +} + +fn EvaluationKind get_evaluation_kind(Type* type) +{ + switch (type->id) + { + case TypeId::void_type: + case TypeId::noreturn: + case TypeId::forward_declaration: + case TypeId::unresolved: + case TypeId::function: + case TypeId::alias: + unreachable(); + case TypeId::integer: + case TypeId::pointer: + case TypeId::bits: + case TypeId::enumerator: + return EvaluationKind::scalar; + case TypeId::array: + case TypeId::structure: + case TypeId::union_type: + return EvaluationKind::aggregate; + } +} + +fn void llvm_initialize(Module* module) +{ + llvm_initialize_all(); + + auto context = LLVMContextCreate(); + auto m = llvm_context_create_module(context, module->name); + auto builder = LLVMCreateBuilderInContext(context); + LLVMDIBuilderRef di_builder = 0; + LLVMMetadataRef di_compile_unit = 0; + LLVMMetadataRef di_file = 0; + + if (module->has_debug_info) + { + di_builder = LLVMCreateDIBuilder(m); + auto last_slash = string_last_character(module->path, '/'); + if (last_slash == string_no_match) + { + report_error(); + } + auto directory = module->path(0, last_slash); + auto file_name = module->path(last_slash + 1); + auto file = LLVMDIBuilderCreateFile(di_builder, (char*)file_name.pointer, file_name.length, (char*)directory.pointer, directory.length); + auto producer_name = string_literal("bloat buster"); + auto is_optimized = build_mode_is_optimized(module->build_mode); + auto flags = string_literal(""); + u32 runtime_version = 0; + auto split_name = string_literal(""); + auto sysroot = string_literal(""); + auto sdk = string_literal(""); + di_compile_unit = LLVMDIBuilderCreateCompileUnit(di_builder, LLVMDWARFSourceLanguageC17, file, (char*)producer_name.pointer, producer_name.length, is_optimized, (char*)flags.pointer, flags.length, runtime_version, (char*)split_name.pointer, split_name.length, LLVMDWARFEmissionFull, 0, 0, is_optimized, (char*)sysroot.pointer, sysroot.length, (char*)sdk.pointer, sdk.length); + module->scope.llvm = di_compile_unit; + } + + module->llvm = { + .context = context, + .module = m, + .builder = builder, + .di_builder = di_builder, + .file = di_file, + .compile_unit = di_compile_unit, + .pointer_type = LLVMPointerTypeInContext(context, 0), + .void_type = LLVMVoidTypeInContext(context), + }; + + for (u64 i = 0; i < (u64)IntrinsicIndex::count; i += 1) + { + String name = intrinsic_names[i]; + module->llvm.intrinsic_table[i].n = LLVMLookupIntrinsicID((char*)name.pointer, name.length); + } +} + +enum class AbiSystemVClass +{ + none, + integer, + sse, + sse_up, + x87, + x87_up, + complex_x87, + memory, +}; + +fn bool contains_no_user_data(Type* type, u64 start, u64 end) +{ + if (get_byte_size(type) <= start) + { + return true; + } + else + { + switch (type->id) + { + case TypeId::structure: + { + trap_raw(); + } break; + case TypeId::array: + { + trap_raw(); + } break; + default: return false; + } + } +} + +fn Type* get_integer_type_at_offset(Module* module, Type* type, u32 offset, Type* source_type, u32 source_offset) +{ + switch (type->id) + { + case TypeId::integer: + { + auto bit_count = type->integer.bit_count; + switch (bit_count) + { + case 64: return type; + case 32: case 16: case 8: + { + assert(offset == 0); + auto start = source_offset + get_byte_size(type); + auto end = source_offset + 8; + + if (contains_no_user_data(source_type, start, end)) + { + return type; + } + } break; + default: + { + trap_raw(); + } break; + } + } break; + default: unreachable(); + } + + auto source_size = get_byte_size(source_type); + auto byte_count = source_size - source_offset; + auto bit_count = byte_count > 8 ? 64 : byte_count * 8; + auto result = integer_type(module, { .bit_count = 64, .is_signed = false }); + return result; +} + +struct AbiSystemVClassify +{ + u64 base_offset; + bool is_variable_argument; + bool is_register_call; +}; + +struct AbiSystemVClassifyResult +{ + AbiSystemVClass r[2]; +}; + +fn AbiSystemVClassifyResult abi_system_v_classify_type(Type* type, AbiSystemVClassify options) +{ + AbiSystemVClassifyResult result = {}; + auto is_memory = options.base_offset >= 8; + auto current_index = is_memory; + auto not_current_index = !is_memory; + assert(current_index != not_current_index); + result.r[current_index] = AbiSystemVClass::memory; + + switch (type->id) + { + case TypeId::void_type: + case TypeId::noreturn: + result.r[current_index] = AbiSystemVClass::none; + break; + case TypeId::bits: + return abi_system_v_classify_type(type->bits.backing_type, options); + case TypeId::enumerator: + return abi_system_v_classify_type(type->enumerator.backing_type, options); + case TypeId::pointer: + result.r[current_index] = AbiSystemVClass::integer; + break; + case TypeId::integer: + { + if (type->integer.bit_count <= 64) + { + result.r[current_index] = AbiSystemVClass::integer; + } + else if (type->integer.bit_count == 128) + { + trap_raw(); + } + else + { + report_error(); + } + } break; + case TypeId::array: + { + trap_raw(); + } break; + case TypeId::structure: + { + trap_raw(); + } break; + case TypeId::alias: + return abi_system_v_classify_type(type->alias.type, options); + default: unreachable(); + } + + return result; +} + +fn bool is_integral_or_enumeration_type(Type* type) +{ + switch (type->id) + { + case TypeId::alias: return is_integral_or_enumeration_type(type->alias.type); + case TypeId::integer: + case TypeId::bits: + return true; + case TypeId::structure: + return false; + default: unreachable(); + } +} + +fn bool is_promotable_integer_type_for_abi(Type* type) +{ + switch (type->id) + { + case TypeId::integer: return type->integer.bit_count < 32; + case TypeId::bits: return is_promotable_integer_type_for_abi(type->bits.backing_type); + case TypeId::alias: return is_promotable_integer_type_for_abi(type->alias.type); + default: unreachable(); + } +} + +struct DirectOptions +{ + Type* semantic_type; + Type* type; + Type* padding; + u32 offset; + u32 alignment; + bool cannot_be_flattened; +}; + +fn void resolve_type_in_place_abi(Module* module, Type* type) +{ + if (!type->llvm.abi) + { + LLVMTypeRef result = 0; + + switch (type->id) + { + case TypeId::void_type: + case TypeId::noreturn: + result = module->llvm.void_type; + break; + case TypeId::integer: + result = LLVMIntTypeInContext(module->llvm.context, type->integer.bit_count); + break; + case TypeId::pointer: + result = module->llvm.pointer_type; + break; + case TypeId::array: + { + trap_raw(); + } break; + default: unreachable(); + } + + assert(result); + type->llvm.abi = result; + } +} + +fn void resolve_type_in_place_memory(Module* module, Type* type) +{ + if (!type->llvm.memory) + { + resolve_type_in_place_abi(module, type); + + LLVMTypeRef result = 0; + + switch (type->id) + { + case TypeId::void_type: + case TypeId::noreturn: + case TypeId::pointer: + result = type->llvm.abi; + break; + case TypeId::integer: + { + auto byte_size = get_byte_size(type); + auto bit_count = byte_size * 8; + result = LLVMIntTypeInContext(module->llvm.context, bit_count); + } break; + default: unreachable(); + } + + assert(result); + type->llvm.memory = result; + + if (type->id == TypeId::bits) + { + assert(type->llvm.memory == type->llvm.abi); + } + } +} + +fn void resolve_type_in_place_debug(Module* module, Type* type) +{ + if (module->has_debug_info) + { + if (!type->llvm.debug) + { + LLVMMetadataRef result = 0; + + switch (type->id) + { + case TypeId::integer: + { + DwarfType dwarf_type = type->integer.bit_count == 1 ? DwarfType::boolean : (type->integer.is_signed ? DwarfType::signed_type : DwarfType::unsigned_type); + LLVMDIFlags flags = {}; + result = LLVMDIBuilderCreateBasicType(module->llvm.di_builder, (char*)type->name.pointer, type->name.length, type->integer.bit_count, (u32)dwarf_type, flags); + } break; + case TypeId::pointer: + { + resolve_type_in_place_debug(module, type->pointer.element_type); + if (type->llvm.debug) + { + trap_raw(); + } + else + { + result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, 64, 64, 0, (char*)type->name.pointer, type->name.length); + } + } break; + default: unreachable(); + } + + assert(result); + type->llvm.debug = result; + } + } +} + +fn void resolve_type_in_place(Module* module, Type* type) +{ + resolve_type_in_place_abi(module, type); + resolve_type_in_place_memory(module, type); + resolve_type_in_place_debug(module, type); +} + +fn bool type_is_abi_equal(Module* module, Type* a, Type* b) +{ + resolve_type_in_place(module, a); + resolve_type_in_place(module, b); + + bool result = a == b; + if (!result) + { + result = a->llvm.abi == b->llvm.abi; + } + return result; +} + +fn AbiInformation abi_system_v_get_direct(Module* module, DirectOptions direct) +{ + AbiInformation result = { + .semantic_type = direct.semantic_type, + .flags = { + .kind = AbiKind::direct, + }, + }; + resolve_type_in_place(module, direct.semantic_type); + resolve_type_in_place(module, direct.type); + if (unlikely(direct.padding)) + { + resolve_type_in_place(module, direct.padding); + } + + result.set_coerce_to_type(direct.type); + result.set_padding_type(direct.type); + result.set_direct_offset(direct.offset); + result.set_direct_alignment(direct.alignment); + result.set_can_be_flattened(!direct.cannot_be_flattened); + + return result; +} + +fn AbiInformation abi_system_classify_return_type(Module* module, Type* semantic_return_type) +{ + auto type_classes = abi_system_v_classify_type(semantic_return_type, {}); + auto low_class = type_classes.r[0]; + auto high_class = type_classes.r[1]; + assert(high_class != AbiSystemVClass::memory || low_class == AbiSystemVClass::memory); + assert(high_class != AbiSystemVClass::sse_up || low_class == AbiSystemVClass::sse); + + Type* low_type = 0; + + switch (low_class) + { + case AbiSystemVClass::none: + { + trap_raw(); + } break; + case AbiSystemVClass::integer: + { + low_type = get_integer_type_at_offset(module, semantic_return_type, 0, semantic_return_type, 0); + + if (high_class == AbiSystemVClass::none && low_type->id == TypeId::integer) + { + if (semantic_return_type->id == TypeId::enumerator) + { + trap_raw(); + } + + if (is_integral_or_enumeration_type(semantic_return_type) && is_promotable_integer_type_for_abi(semantic_return_type)) + { + trap_raw(); + } + } + } break; + default: unreachable(); + } + + Type* high_type = 0; + + switch (high_class) + { + case AbiSystemVClass::none: + break; + case AbiSystemVClass::integer: + { + trap_raw(); + } break; + + default: unreachable(); + } + + if (high_type) + { + trap_raw(); + } + + auto result = abi_system_v_get_direct(module, { + .semantic_type = semantic_return_type, + .type = low_type, + }); + return result; +} + +struct AttributeBuildOptions +{ + AbiInformation return_abi; + Slice argument_abis; + Slice abi_argument_types; + Type* abi_return_type; + FunctionAttributes attributes; + bool call_site; +}; + +struct AllocaOptions +{ + Type* type; + String name = string_literal(""); + u32 alignment; + bool is_valid_alignment; +}; + +fn LLVMValueRef create_alloca(Module* module, AllocaOptions options) +{ + auto abi_type = options.type; + resolve_type_in_place(module, abi_type); + assert(options.name.pointer[options.name.length] == 0); + + u32 alignment; + if (options.is_valid_alignment) + { + alignment = options.alignment; + } + else + { + alignment = get_byte_alignment(abi_type); + } + + auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, 0, alignment, options.name); + return alloca; +} + +struct StoreOptions +{ + LLVMValueRef source; + LLVMValueRef destination; + Type* type; + u32 alignment; + bool is_valid_alignment; +}; + +fn void create_store(Module* module, StoreOptions options) +{ + assert(options.source); + assert(options.destination); + assert(options.type); + + auto resolved_type = resolve_alias(module, options.type); + resolve_type_in_place(module, resolved_type); + + LLVMValueRef source_value; + + LLVMTypeRef memory_type = resolved_type->llvm.memory; + if (resolved_type->llvm.abi == memory_type) + { + source_value = options.source; + } + else + { + source_value = LLVMBuildIntCast2(module->llvm.builder, options.source, memory_type, type_is_signed(resolved_type), ""); + } + + u32 alignment; + if (options.is_valid_alignment) + { + alignment = options.alignment; + } + else + { + alignment = get_byte_alignment(resolved_type); + } + + auto store = LLVMBuildStore(module->llvm.builder, source_value, options.destination); + LLVMSetAlignment(store, alignment); +} + +fn BBLLVMAttributeList build_attribute_list(Module* module, AttributeBuildOptions options) +{ + resolve_type_in_place(module, options.return_abi.semantic_type); + BBLLVMAttributeListOptions attributes = {}; + + attributes.return_ = { + .semantic_type = options.return_abi.semantic_type->llvm.memory, + .abi_type = options.abi_return_type->llvm.abi, + .dereferenceable_bytes = 0, + .alignment = 0, + .no_alias = false, + .non_null = false, + .no_undef = false, + .sign_extend = options.return_abi.flags.kind == AbiKind::extend and options.return_abi.flags.sign_extension, + .zero_extend = options.return_abi.flags.kind == AbiKind::extend and !options.return_abi.flags.sign_extension, + .in_reg = false, + .no_fp_class = 0, // TODO: this is a struct + .struct_return = false, + .writable = false, + .dead_on_unwind = false, + .in_alloca = false, + .dereferenceable = false, + .dereferenceable_or_null = false, + .nest = false, + .by_value = false, + .by_reference = false, + .no_capture = false, + }; + + BBLLVMArgumentAttributes argument_attribute_buffer[128]; + auto argument_attributes = Slice{ .pointer = argument_attribute_buffer, .length = options.abi_argument_types.length }; + + if (options.return_abi.flags.kind == AbiKind::indirect) + { + trap_raw(); + } + + for (auto& abi: options.argument_abis) + { + trap_raw(); + } + + attributes.function = { + .prefer_vector_width = {}, + .stack_protector_buffer_size = {}, + .definition_probe_stack = {}, + .definition_stack_probe_size = {}, + .flags0 = { + .noreturn = options.return_abi.semantic_type == noreturn_type(module), + .cmse_ns_call = false, + .nounwind = true, + .returns_twice = false, + .cold = false, + .hot = false, + .no_duplicate = false, + .convergent = false, + .no_merge = false, + .will_return = false, + .no_caller_saved_registers = false, + .no_cf_check = false, + .no_callback = false, + .alloc_size = false, // TODO + .uniform_work_group_size = false, + .aarch64_pstate_sm_body = false, + .aarch64_pstate_sm_enabled = false, + .aarch64_pstate_sm_compatible = false, + .aarch64_preserves_za = false, + .aarch64_in_za = false, + .aarch64_out_za = false, + .aarch64_inout_za = false, + .aarch64_preserves_zt0 = false, + .aarch64_in_zt0 = false, + .aarch64_out_zt0 = false, + .aarch64_inout_zt0 = false, + .optimize_for_size = false, + .min_size = false, + .no_red_zone = false, + .indirect_tls_seg_refs = false, + .no_implicit_floats = false, + .sample_profile_suffix_elision_policy = false, + .memory_none = false, + .memory_readonly = false, + .memory_inaccessible_or_arg_memory_only = false, + .memory_arg_memory_only = false, + .strict_fp = false, + .no_inline = options.attributes.inline_behavior == InlineBehavior::no_inline, + .always_inline = options.attributes.inline_behavior == InlineBehavior::always_inline, + .guard_no_cf = false, + // TODO: branch protection function attributes + // TODO: cpu features + + // CALL-SITE ATTRIBUTES + .call_no_builtins = false, + + // DEFINITION-SITE ATTRIBUTES + .definition_frame_pointer_kind = module->has_debug_info ? BBLLVMFramePointerKind::all : BBLLVMFramePointerKind::none, + .definition_less_precise_fpmad = false, + .definition_null_pointer_is_valid = false, + .definition_no_trapping_fp_math = false, + .definition_no_infs_fp_math = false, + .definition_no_nans_fp_math = false, + .definition_approx_func_fp_math = false, + .definition_unsafe_fp_math = false, + .definition_use_soft_float = false, + .definition_no_signed_zeroes_fp_math = false, + .definition_stack_realignment = false, + .definition_backchain = false, + .definition_split_stack = false, + .definition_speculative_load_hardening = false, + .definition_zero_call_used_registers = ZeroCallUsedRegsKind::all, + // TODO: denormal builtins + .definition_non_lazy_bind = false, + .definition_cmse_nonsecure_entry = false, + .definition_unwind_table_kind = BBLLVMUWTableKind::None, + }, + .flags1 = { + .definition_disable_tail_calls = false, + .definition_stack_protect_strong = false, + .definition_stack_protect = false, + .definition_stack_protect_req = false, + .definition_aarch64_new_za = false, + .definition_aarch64_new_zt0 = false, + .definition_optimize_none = false, + .definition_naked = !options.call_site and options.attributes.naked, + .definition_inline_hint = !options.call_site and options.attributes.inline_behavior == InlineBehavior::inline_hint, + }, + }; + + auto attribute_list = llvm_attribute_list_build(module->llvm.context, &attributes, options.call_site); + return attribute_list; +} + +fn void check_types(Module* module, Type* expected, Type* source) +{ + assert(expected); + assert(source); + + if (expected != source) + { + auto resolved_expected = resolve_alias(module, expected); + auto resolved_source = resolve_alias(module, source); + + if (resolved_expected != resolved_source) + { + auto is_dst_p_and_source_int = resolved_expected->id == TypeId::pointer && resolved_source->id == TypeId::integer; + if (!is_dst_p_and_source_int) + { + report_error(); + } + } + } +} + +fn void typecheck(Module* module, Type* expected, Type* source) +{ + if (expected) + { + check_types(module, expected, source); + } +} + +fn void analyze_type(Module* module, Value* value, Type* expected_type) +{ + assert(!value->type); + assert(!value->llvm); + + if (expected_type && expected_type->id == TypeId::unresolved) + { + trap_raw(); + } + + Type* value_type = 0; + + switch (value->id) + { + case ValueId::constant_integer: + { + if (!expected_type) + { + report_error(); + } + + resolve_type_in_place(module, expected_type); + auto* resolved_type = resolve_alias(module, expected_type); + switch (resolved_type->id) + { + case TypeId::integer: + { + if (value->constant_integer.is_signed) + { + if (resolved_type->integer.is_signed) + { + report_error(); + } + + trap_raw(); + } + else + { + auto bit_count = resolved_type->integer.bit_count; + auto max_value = bit_count == 64 ? ~(u64)0 : ((u64)1 << (bit_count - resolved_type->integer.is_signed)) - 1; + + if (value->constant_integer.value > max_value) + { + report_error(); + } + + value_type = expected_type; + } + } break; + case TypeId::pointer: value_type = integer_type(module, { .bit_count = 64, .is_signed = false }); break; + default: trap_raw(); + } + + typecheck(module, expected_type, value_type); + } break; + default: unreachable(); + } + + assert(value_type); + value->type = value_type; +} + +fn LLVMTypeRef get_llvm_type(Type* type, TypeKind type_kind) +{ + switch (type_kind) + { + case TypeKind::abi: + return type->llvm.abi; + case TypeKind::memory: + return type->llvm.memory; + } +} + +fn void emit_value(Module* module, Value* value, TypeKind type_kind) +{ + assert(value->type); + assert(!value->llvm); + auto resolved_type = resolve_alias(module, value->type); + resolve_type_in_place(module, resolved_type); + + auto must_be_constant = !module->current_function && !module->current_macro_instantiation; + + LLVMValueRef llvm_value = 0; + switch (value->id) + { + case ValueId::constant_integer: + { + auto llvm_integer_type = get_llvm_type(resolved_type, type_kind); + llvm_value = LLVMConstInt(llvm_integer_type, value->constant_integer.value, value->constant_integer.is_signed); + } break; + default: unreachable(); + } + + assert(llvm_value); + value->llvm = llvm_value; +} + +fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type, Value* right) +{ + assert(!right->llvm); + auto pointer_type = left_type; + auto value_type = right->type; + assert(pointer_type); + assert(value_type); + resolve_type_in_place(module, pointer_type); + resolve_type_in_place(module, value_type); + + auto resolved_pointer_type = resolve_alias(module, pointer_type); + auto resolved_value_type = resolve_alias(module, value_type); + assert(resolved_pointer_type->id == TypeId::pointer); + assert(resolved_pointer_type->pointer.element_type == resolved_value_type); + + auto type_kind = TypeKind::memory; + + auto evaluation_kind = get_evaluation_kind(resolved_value_type); + switch (evaluation_kind) + { + case EvaluationKind::scalar: + { + emit_value(module, right, type_kind); + create_store(module, { + .source = right->llvm, + .destination = left_llvm, + .type = resolved_value_type, + }); + } break; + default: unreachable(); + } +} + +fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u32* last_line, u32* last_column, LLVMMetadataRef* last_debug_location) +{ + Global* parent_function_global; + if (module->current_function) + { + parent_function_global = module->current_function; + } + else if (module->current_macro_instantiation) + { + parent_function_global = module->current_macro_instantiation->instantiation_function; + } + else + { + report_error(); + } + + auto* llvm_function = parent_function_global->variable.storage->llvm; + assert(llvm_function); + + if (module->has_debug_info) + { + if (statement->line != *last_line || statement->column != *last_column) + { + auto new_location = LLVMDIBuilderCreateDebugLocation(module->llvm.context, statement->line, statement->column, scope->llvm, module->llvm.inlined_at); + *last_debug_location = new_location; + LLVMSetCurrentDebugLocation2(module->llvm.builder, new_location); + *last_line = statement->line; + *last_column = statement->column; + } + } + + switch (statement->id) + { + case StatementId::return_st: + { + if (module->current_function) + { + auto& function_type = parent_function_global->variable.storage->type->pointer.element_type->function; + auto& return_abi = function_type.return_abi; + auto return_value = statement->return_st; + + switch (return_abi.semantic_type->id) + { + case TypeId::void_type: + { + if (return_value) + { + report_error(); + } + } break; + case TypeId::noreturn: + { + report_error(); + } break; + default: + { + if (module->has_debug_info) + { + LLVMSetCurrentDebugLocation2(module->llvm.builder, *last_debug_location); + } + + auto return_alloca = module->current_function->variable.storage->function.llvm.return_alloca; + if (!return_alloca) + { + report_error(); + } + + if (!return_value) + { + report_error(); + } + + analyze_type(module, return_value, return_abi.semantic_type); + auto pointer_type = get_pointer_type(module, return_abi.semantic_type); + emit_assignment(module, return_alloca, pointer_type, return_value); + } break; + } + + auto return_block = module->current_function->variable.storage->function.llvm.return_block; + LLVMBuildBr(module->llvm.builder, return_block); + LLVMClearInsertionPosition(module->llvm.builder); + } + else if (module->current_macro_instantiation) + { + trap_raw(); + } + else + { + report_error(); + } + } break; + default: unreachable(); + } +} + +fn void analyze_block(Module* module, Block* block) +{ + if (module->has_debug_info) + { + auto lexical_block = LLVMDIBuilderCreateLexicalBlock(module->llvm.di_builder, block->scope.parent->llvm, module->llvm.file, block->scope.line, block->scope.column); + block->scope.llvm = lexical_block; + } + + u32 last_line = 0; + u32 last_column = 0; + LLVMMetadataRef last_debug_location = 0; + + for (auto* statement = block->first_statement; statement; statement = statement->next) + { + analyze_statement(module, &block->scope, statement, &last_line, &last_column, &last_debug_location); + } +} + + void emit(Module* module) { + llvm_initialize(module); + for (auto* global = module->first_global; global; global = global->next) + { + switch (global->variable.storage->id) + { + case ValueId::function: + case ValueId::external_function: + { + auto function_type = &global->variable.storage->type->pointer.element_type->function; + function_type->argument_abis = arena_allocate(module->arena, function_type->semantic_argument_types.length); + auto resolved_calling_convention = resolve_calling_convention(function_type->calling_convention); + auto is_reg_call = resolved_calling_convention == ResolvedCallingConvention::system_v && false; // TODO: regcall calling convention + + LLVMTypeRef llvm_abi_argument_type_buffer[64]; + + switch (resolved_calling_convention) + { + case ResolvedCallingConvention::system_v: + { + function_type->available_registers = { + .system_v = { + .gpr = (u32)(is_reg_call ? 11 : 6), + .sse = (u32)(is_reg_call ? 16 : 8), + }, + }; + function_type->return_abi = abi_system_classify_return_type(module, function_type->semantic_return_type); + auto return_abi_kind = function_type->return_abi.flags.kind; + + Type* abi_argument_type_buffer[64]; + u16 abi_argument_type_count = 0; + + Type* abi_return_type; + switch (return_abi_kind) + { + case AbiKind::direct: + case AbiKind::extend: + { + abi_return_type = function_type->return_abi.coerce_to_type; + } break; + case AbiKind::ignore: + case AbiKind::indirect: + { + abi_return_type = void_type(module); + } break; + default: unreachable(); // TODO + } + assert(abi_return_type); + function_type->abi_return_type = abi_return_type; + resolve_type_in_place(module, abi_return_type); + + if (function_type->return_abi.flags.kind == AbiKind::indirect) + { + trap_raw(); + } + + auto required_argument_count = function_type->semantic_argument_types.length; + + for (auto abi: function_type->argument_abis) + { + trap_raw(); + } + + auto abi_argument_types = new_type_array(module, abi_argument_type_count); + memcpy(abi_argument_types.pointer, abi_argument_type_buffer, sizeof(abi_argument_type_buffer[0]) * abi_argument_type_count); + function_type->abi_argument_types = abi_argument_types; + } break; + case ResolvedCallingConvention::win64: + { + report_error(); + } break; + case ResolvedCallingConvention::count: unreachable(); + } + + auto llvm_function_type = LLVMFunctionType(function_type->abi_return_type->llvm.abi, llvm_abi_argument_type_buffer, (u32)function_type->abi_argument_types.length, function_type->is_variable_arguments); + + LLVMMetadataRef subroutine_type = 0; + if (module->has_debug_info) + { + LLVMMetadataRef debug_argument_type_buffer[64]; + Slice debug_argument_types = { .pointer = debug_argument_type_buffer, .length = function_type->argument_abis.length + 1 + function_type->is_variable_arguments }; + debug_argument_types[0] = function_type->return_abi.semantic_type->llvm.debug; + assert(debug_argument_types[0]); + + auto debug_argument_type_slice = debug_argument_types(1)(0, function_type->argument_abis.length); + + for (u64 i = 0; i < function_type->argument_abis.length; i += 1) + { + auto& argument_abi = function_type->argument_abis[i]; + auto* debug_argument_type = &debug_argument_type_slice[i]; + *debug_argument_type = argument_abi.semantic_type->llvm.debug; + assert(*debug_argument_type); + } + + if (function_type->is_variable_arguments) + { + auto void_ty = void_type(module); + assert(void_ty->llvm.debug); + debug_argument_types[function_type->argument_abis.length + 1] = void_ty->llvm.debug; + } + + LLVMDIFlags flags = {}; + subroutine_type = LLVMDIBuilderCreateSubroutineType(module->llvm.di_builder, module->llvm.file, debug_argument_types.pointer, (u32)debug_argument_types.length, flags); + } + + global->variable.storage->type->pointer.element_type->llvm.abi = llvm_function_type; + global->variable.storage->type->pointer.element_type->llvm.debug = subroutine_type; + + LinkageType llvm_linkage_type; + switch (global->linkage) + { + case Linkage::internal: llvm_linkage_type = LinkageType::internal; break; + case Linkage::external: llvm_linkage_type = LinkageType::external; break; + } + unsigned address_space = 0; + auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, llvm_linkage_type, address_space, global->variable.name); + global->variable.storage->llvm = llvm_function; + + LLVMCallConv cc; + switch (function_type->calling_convention) + { + case CallingConvention::c: cc = LLVMCCallConv; break; + case CallingConvention::count: unreachable(); + } + LLVMSetFunctionCallConv(llvm_function, cc); + + assert(global->variable.storage->id == ValueId::function); + auto attribute_list = build_attribute_list(module, { + .return_abi = function_type->return_abi, + .argument_abis = function_type->argument_abis, + .abi_argument_types = function_type->abi_argument_types, + .abi_return_type = function_type->abi_return_type, + .attributes = global->variable.storage->function.attributes, + .call_site = false, + }); + llvm_function_set_attributes(llvm_function, attribute_list); + + LLVMMetadataRef subprogram = 0; + auto is_definition = global->variable.storage->id == ValueId::function; + + if (module->has_debug_info) + { + auto is_local_to_unit = global->linkage == Linkage::internal; + auto line = global->variable.line; + auto scope_line = line + 1; + LLVMDIFlags flags = {}; + auto is_optimized = build_mode_is_optimized(module->build_mode); + subprogram = LLVMDIBuilderCreateFunction(module->llvm.di_builder, module->scope.llvm, (char*)global->variable.name.pointer, global->variable.name.length, (char*)global->variable.name.pointer, global->variable.name.length, module->llvm.file, line, subroutine_type, is_local_to_unit, is_definition, scope_line, flags, is_optimized); + } + + if (is_definition) + { + global->variable.storage->function.scope.llvm = subprogram; + + module->current_function = global; + + auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("entry"), llvm_function); + auto return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("return_block"), llvm_function); + global->variable.storage->function.llvm.return_block = return_block; + + LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); + LLVMSetCurrentDebugLocation2(module->llvm.builder, 0); + + auto return_abi_kind = function_type->return_abi.flags.kind; + switch (return_abi_kind) + { + case AbiKind::indirect: + { + trap_raw(); + } break; + case AbiKind::in_alloca: + { + trap_raw(); + } break; + default: + { + auto alloca = create_alloca(module, { + .type = function_type->return_abi.semantic_type, + .name = string_literal("retval"), + }); + global->variable.storage->function.llvm.return_alloca = alloca; + } break; + case AbiKind::ignore: break; + } + + for (auto& argument : global->variable.storage->function.arguments) + { + trap_raw(); + } + + analyze_block(module, global->variable.storage->function.block); + + auto* insert_block = LLVMGetInsertBlock(module->llvm.builder); + if (insert_block) + { + trap_raw(); + } + else + { + bool is_reachable = false; + + if (llvm_value_has_one_use((LLVMValueRef)return_block)) + { + auto user = llvm_basic_block_user_begin(return_block); + is_reachable = LLVMIsABranchInst(user) && !LLVMIsConditional(user) && LLVMGetSuccessor(user, 0) == return_block; + if (is_reachable) + { + LLVMPositionBuilderAtEnd(module->llvm.builder, LLVMGetInstructionParent(user)); + LLVMInstructionEraseFromParent(user); + // llvm_basic_block_delete(return_block); + } + } + + if (!is_reachable) + { + trap_raw(); + } + } + + if (module->has_debug_info) + { + LLVMSetCurrentDebugLocation2(module->llvm.builder, 0); + auto subprogram = LLVMGetSubprogram(llvm_function); + LLVMDIBuilderFinalizeSubprogram(module->llvm.di_builder, subprogram); + } + + if (function_type->return_abi.semantic_type == noreturn_type(module) || global->variable.storage->function.attributes.naked) + { + LLVMBuildUnreachable(module->llvm.builder); + } + else if (function_type->return_abi.semantic_type == void_type(module)) + { + LLVMBuildRetVoid(module->llvm.builder); + } + else + { + LLVMValueRef return_value = 0; + + switch (return_abi_kind) + { + case AbiKind::direct: + case AbiKind::extend: + { + dump_module(module); + auto return_alloca = global->variable.storage->function.llvm.return_alloca; + auto coerce_to_type = function_type->return_abi.get_coerce_to_type(); + if (coerce_to_type->id != TypeId::structure && type_is_abi_equal(module, coerce_to_type, function_type->return_abi.semantic_type) && function_type->return_abi.attributes.direct.offset == 0) + { + auto store = llvm_find_return_value_dominating_store(module->llvm.builder, return_alloca, function_type->return_abi.semantic_type->llvm.abi); + if (store) + { + return_value = LLVMGetOperand(store, 0); + auto alloca = LLVMGetOperand(store, 1); + assert(alloca == return_alloca); + LLVMInstructionEraseFromParent(store); + assert(llvm_value_use_empty(alloca)); + LLVMInstructionEraseFromParent(alloca); + } + else + { + trap_raw(); + } + } + else + { + trap_raw(); + } + } break; + case AbiKind::indirect: + { + trap_raw(); + } break; + default: unreachable(); + } + + LLVMBuildRet(module->llvm.builder, return_value); + } + + // END OF SCOPE + module->current_function = 0; + } + } break; + case ValueId::global: + { + trap_raw(); + } break; + default: report_error(); + } + } + + if (module->has_debug_info) + { + LLVMDIBuilderFinalize(module->llvm.di_builder); + } + + String verification_error_message = {}; + if (!llvm_module_verify(module->llvm.module, &verification_error_message)) + { + dump_module(module); + print(verification_error_message); + print(string_literal("\n")); + } } diff --git a/src/lib.h b/src/lib.h index 6281273..eb30793 100644 --- a/src/lib.h +++ b/src/lib.h @@ -8,6 +8,7 @@ #define breakpoint() __builtin_debugtrap() #define string_literal_length(s) (sizeof(s) - 1) #define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), }) +#define split_string_literal(s) (char*)(s), string_literal_length(s) #define offsetof(S, f) __builtin_offsetof(S, f) #define array_length(arr) sizeof(arr) / sizeof((arr)[0]) diff --git a/src/llvm.cpp b/src/llvm.cpp index 60324b0..bea43e3 100644 --- a/src/llvm.cpp +++ b/src/llvm.cpp @@ -26,97 +26,112 @@ #include "lld/Common/CommonLinkerContext.h" -using namespace llvm; - -fn StringRef string_ref(String string) +fn llvm::StringRef string_ref(String string) { - return StringRef((char*)string.pointer, string.length); + return llvm::StringRef((char*)string.pointer, string.length); } -EXPORT Module* llvm_context_create_module(LLVMContext& context, String name) +EXPORT LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name) { - return new Module(string_ref(name), context); + auto module = new llvm::Module(string_ref(name), *llvm::unwrap(context)); + return wrap(module); } -EXPORT unsigned llvm_integer_type_get_bit_count(const IntegerType& integer_type) +EXPORT unsigned llvm_integer_type_get_bit_count(const llvm::IntegerType& integer_type) { auto result = integer_type.getBitWidth(); return result; } -EXPORT GlobalVariable* llvm_module_create_global_variable(Module& module, Type* type, bool is_constant, GlobalValue::LinkageTypes linkage_type, Constant* initial_value, String name, GlobalVariable* before, GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized) +EXPORT llvm::GlobalVariable* llvm_module_create_global_variable(llvm::Module& module, llvm::Type* type, bool is_constant, llvm::GlobalValue::LinkageTypes linkage_type, llvm::Constant* initial_value, String name, llvm::GlobalVariable* before, llvm::GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized) { - auto* global = new GlobalVariable(module, type, is_constant, linkage_type, initial_value, string_ref(name), before, thread_local_mode, address_space, externally_initialized); + auto* global = new llvm::GlobalVariable(module, type, is_constant, linkage_type, initial_value, string_ref(name), before, thread_local_mode, address_space, externally_initialized); return global; } -EXPORT void llvm_global_variable_add_debug_info(GlobalVariable& global, DIGlobalVariableExpression* debug_global_variable) +EXPORT void llvm_global_variable_add_debug_info(llvm::GlobalVariable& global, llvm::DIGlobalVariableExpression* debug_global_variable) { global.addDebugInfo(debug_global_variable); } -EXPORT void llvm_global_variable_delete(GlobalVariable* global) +EXPORT void llvm_global_variable_delete(llvm::GlobalVariable* global) { delete global; } -EXPORT void llvm_subprogram_replace_type(DISubprogram& subprogram, DISubroutineType* subroutine_type) +EXPORT void llvm_subprogram_replace_type(llvm::DISubprogram& subprogram, llvm::DISubroutineType* subroutine_type) { subprogram.replaceType(subroutine_type); } -EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, String name) +EXPORT LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LinkageType linkage_type, unsigned address_space, String name) { - auto* function = Function::Create(function_type, linkage_type, address_space, string_ref(name), module); - return function; + llvm::GlobalValue::LinkageTypes llvm_linkage_type; + switch (linkage_type) + { + case LinkageType::external: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break; + case LinkageType::available_externally: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage; break; + case LinkageType::link_once_any: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage; break; + case LinkageType::link_once_odr: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage; break; + case LinkageType::weak_any: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakAnyLinkage; break; + case LinkageType::weak_odr: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakODRLinkage; break; + case LinkageType::appending: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AppendingLinkage; break; + case LinkageType::internal: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::InternalLinkage; break; + case LinkageType::private_: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::PrivateLinkage; break; + case LinkageType::external_weak: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break; + case LinkageType::common: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::CommonLinkage; break; + } + auto* function = llvm::Function::Create(llvm::unwrap(function_type), llvm_linkage_type, address_space, string_ref(name), llvm::unwrap(module)); + return wrap(function); } -EXPORT StructType* llvm_context_create_forward_declared_struct_type(LLVMContext& context, String name) +EXPORT llvm::StructType* llvm_context_create_forward_declared_struct_type(llvm::LLVMContext& context, String name) { - auto* struct_type = StructType::create(context, string_ref(name)); + auto* struct_type = llvm::StructType::create(context, string_ref(name)); return struct_type; } -EXPORT StructType* llvm_context_create_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, String name, bool is_packed) +EXPORT llvm::StructType* llvm_context_create_struct_type(llvm::LLVMContext& context, llvm::Type** type_pointer, size_t type_count, String name, bool is_packed) { - auto types = ArrayRef(type_pointer, type_count); - auto* struct_type = StructType::create(context, types, string_ref(name), is_packed); + auto types = llvm::ArrayRef(type_pointer, type_count); + auto* struct_type = llvm::StructType::create(context, types, string_ref(name), is_packed); return struct_type; } -EXPORT StructType* llvm_context_get_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, bool is_packed) +EXPORT llvm::StructType* llvm_context_get_struct_type(llvm::LLVMContext& context, llvm::Type** type_pointer, size_t type_count, bool is_packed) { - auto types = ArrayRef(type_pointer, type_count); - auto* struct_type = StructType::get(context, types, is_packed); + auto types = llvm::ArrayRef(type_pointer, type_count); + auto* struct_type = llvm::StructType::get(context, types, is_packed); return struct_type; } -EXPORT BasicBlock* llvm_context_create_basic_block(LLVMContext& context, String name, Function* parent) +EXPORT LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function) { - auto* basic_block = BasicBlock::Create(context, string_ref(name), parent); - return basic_block; + auto* basic_block = llvm::BasicBlock::Create(*llvm::unwrap(context), string_ref(name), llvm::unwrap(parent_function)); + return wrap(basic_block); } -EXPORT bool llvm_value_has_one_use(Value& value) +EXPORT bool llvm_value_has_one_use(LLVMValueRef value) { - auto result = value.hasOneUse(); + auto v = llvm::unwrap(value); + auto result = v->hasOneUse(); return result; } -EXPORT Value* llvm_basic_block_user_begin(BasicBlock* basic_block) +EXPORT LLVMValueRef llvm_basic_block_user_begin(LLVMBasicBlockRef basic_block) { - Value* value = *basic_block->user_begin(); - return value; + llvm::Value* value = *llvm::unwrap(basic_block)->user_begin(); + return wrap(value); } -EXPORT void llvm_basic_block_delete(BasicBlock* basic_block) +EXPORT void llvm_basic_block_delete(LLVMBasicBlockRef basic_block) { - delete basic_block; + delete llvm::unwrap(basic_block); } -EXPORT BranchInst* llvm_value_to_branch(Value* value) +EXPORT llvm::BranchInst* llvm_value_to_branch(llvm::Value* value) { - auto* result = dyn_cast(value); + auto* result = dyn_cast(value); return result; } @@ -124,7 +139,7 @@ EXPORT BranchInst* llvm_value_to_branch(Value* value) // for something immediately preceding the IP. Sometimes this can // happen with how we generate implicit-returns; it can also happen // with noreturn cleanups. -fn StoreInst* get_store_if_valid(User* user, Value* return_alloca, Type* element_type) +fn llvm::StoreInst* get_store_if_valid(llvm::User* user, llvm::Value* return_alloca, llvm::Type* element_type) { auto *SI = dyn_cast(user); if (!SI || SI->getPointerOperand() != return_alloca || @@ -142,62 +157,66 @@ fn StoreInst* get_store_if_valid(User* user, Value* return_alloca, Type* element // copy of static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { // in clang/lib/CodeGen/CGCall.cpp:3526 in LLVM 19 -EXPORT StoreInst* llvm_find_return_value_dominating_store(IRBuilder<>& builder, Value* return_alloca, Type* element_type) +EXPORT LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et) { - // Check if a User is a store which pointerOperand is the ReturnValue. - // We are looking for stores to the ReturnValue, not for stores of the - // ReturnValue to some other location. - if (!return_alloca->hasOneUse()) { - llvm::BasicBlock *IP = builder.GetInsertBlock(); - if (IP->empty()) return nullptr; + auto builder = llvm::unwrap(b); + auto return_alloca = llvm::unwrap(ra); + auto element_type = llvm::unwrap(et); + // Check if a User is a store which pointerOperand is the ReturnValue. + // We are looking for stores to the ReturnValue, not for stores of the + // ReturnValue to some other location. + if (!return_alloca->hasOneUse()) { + llvm::BasicBlock *IP = builder->GetInsertBlock(); + if (IP->empty()) return nullptr; - // Look at directly preceding instruction, skipping bitcasts and lifetime - // markers. - for (llvm::Instruction &I : make_range(IP->rbegin(), IP->rend())) { - if (isa(&I)) - continue; - if (auto *II = dyn_cast(&I)) - if (II->getIntrinsicID() == llvm::Intrinsic::lifetime_end) - continue; + // Look at directly preceding instruction, skipping bitcasts and lifetime + // markers. + for (llvm::Instruction &I : make_range(IP->rbegin(), IP->rend())) { + if (isa(&I)) + continue; + if (auto *II = dyn_cast(&I)) + if (II->getIntrinsicID() == llvm::Intrinsic::lifetime_end) + continue; - return get_store_if_valid(&I, return_alloca, element_type); + return wrap(get_store_if_valid(&I, return_alloca, element_type)); + } + return nullptr; } - return nullptr; - } - llvm::StoreInst *store = get_store_if_valid(return_alloca->user_back(), return_alloca, element_type); - if (!store) return nullptr; + llvm::StoreInst *store = get_store_if_valid(return_alloca->user_back(), return_alloca, element_type); + if (!store) return nullptr; - // Now do a first-and-dirty dominance check: just walk up the - // single-predecessors chain from the current insertion point. - llvm::BasicBlock *StoreBB = store->getParent(); - llvm::BasicBlock *IP = builder.GetInsertBlock(); - llvm::SmallPtrSet SeenBBs; - while (IP != StoreBB) { - if (!SeenBBs.insert(IP).second || !(IP = IP->getSinglePredecessor())) - return nullptr; - } + // Now do a first-and-dirty dominance check: just walk up the + // single-predecessors chain from the current insertion point. + llvm::BasicBlock *StoreBB = store->getParent(); + llvm::BasicBlock *IP = builder->GetInsertBlock(); + llvm::SmallPtrSet SeenBBs; + while (IP != StoreBB) { + if (!SeenBBs.insert(IP).second || !(IP = IP->getSinglePredecessor())) + return nullptr; + } - // Okay, the store's basic block dominates the insertion point; we - // can do our thing. - return store; + // Okay, the store's basic block dominates the insertion point; we + // can do our thing. + return wrap(store); } -EXPORT bool llvm_value_use_empty(Value& value) +EXPORT bool llvm_value_use_empty(LLVMValueRef value) { - return value.use_empty(); + return llvm::unwrap(value)->use_empty(); } -EXPORT bool llvm_basic_block_is_empty(BasicBlock& basic_block) +EXPORT bool llvm_basic_block_is_empty(llvm::BasicBlock& basic_block) { return basic_block.empty(); } -EXPORT AllocaInst* llvm_builder_create_alloca(IRBuilder<>& builder, Type* type, unsigned address_space, String name) +EXPORT LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, unsigned address_space, u32 alignment, String name) { - const DataLayout &data_layout = builder.GetInsertBlock()->getDataLayout(); - Align alignment = data_layout.getABITypeAlign(type); - return builder.Insert(new AllocaInst(type, address_space, 0, alignment), string_ref(name)); + auto& builder = *llvm::unwrap(b); + const llvm::DataLayout &data_layout = builder.GetInsertBlock()->getDataLayout(); + auto llvm_alignment = llvm::Align(alignment); + return wrap(builder.Insert(new llvm::AllocaInst(llvm::unwrap(type), address_space, 0, llvm_alignment), string_ref(name))); } enum class BBLLVMAttributeFramePointerKind : u8 @@ -263,445 +282,312 @@ enum class BBLLVMFPClassTest : unsigned AllFlags = Nan | Inf | Finite, }; -enum class BBLLVMUWTableKind +fn llvm::AttributeSet build_argument_attributes(LLVMContextRef context, BBLLVMArgumentAttributes* attributes) { - None = 0, ///< No unwind table requested - Sync = 1, ///< "Synchronous" unwind tables - Async = 2, ///< "Asynchronous" unwind tables (instr precise) - Default = 2, -}; + llvm::AttrBuilder builder(*llvm::unwrap(context)); -struct BBLLVMArgumentAttributes -{ - Type* semantic_type; - Type* abi_type; - u64 dereferenceable_bytes; - u32 alignment; - u32 no_alias:1; - u32 non_null:1; - u32 no_undef:1; - u32 sign_extend:1; - u32 zero_extend:1; - u32 in_reg:1; - u32 no_fp_class:10; - u32 struct_return:1; - u32 writable:1; - u32 dead_on_unwind:1; - u32 in_alloca:1; - u32 dereferenceable:1; - u32 dereferenceable_or_null:1; - u32 nest:1; - u32 by_value:1; - u32 by_reference:1; - u32 no_capture:1; - u32 _:6; -}; - -static_assert(sizeof(BBLLVMArgumentAttributes) == 2 * sizeof(Type*) + 2 * sizeof(u64)); - -fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgumentAttributes& attributes) -{ - AttrBuilder builder(context); - - if (attributes.alignment) + if (attributes->alignment) { - builder.addAlignmentAttr(attributes.alignment); + builder.addAlignmentAttr(attributes->alignment); } - if (attributes.no_alias) + if (attributes->no_alias) { - builder.addAttribute(Attribute::NoAlias); + builder.addAttribute(llvm::Attribute::NoAlias); } - if (attributes.non_null) + if (attributes->non_null) { - builder.addAttribute(Attribute::NonNull); + builder.addAttribute(llvm::Attribute::NonNull); } - if (attributes.no_undef) + if (attributes->no_undef) { - builder.addAttribute(Attribute::NoUndef); + builder.addAttribute(llvm::Attribute::NoUndef); } - if (attributes.sign_extend) + if (attributes->sign_extend) { - builder.addAttribute(Attribute::SExt); + builder.addAttribute(llvm::Attribute::SExt); } - if (attributes.zero_extend) + if (attributes->zero_extend) { - builder.addAttribute(Attribute::ZExt); + builder.addAttribute(llvm::Attribute::ZExt); } - if (attributes.in_reg) + if (attributes->in_reg) { - builder.addAttribute(Attribute::InReg); + builder.addAttribute(llvm::Attribute::InReg); } - if (attributes.no_fp_class) + if (attributes->no_fp_class) { __builtin_trap(); // TODO } - if (attributes.struct_return) + if (attributes->struct_return) { - builder.addStructRetAttr(attributes.semantic_type); + builder.addStructRetAttr(llvm::unwrap(attributes->semantic_type)); } - if (attributes.writable) + if (attributes->writable) { - builder.addAttribute(Attribute::Writable); + builder.addAttribute(llvm::Attribute::Writable); } - if (attributes.dead_on_unwind) + if (attributes->dead_on_unwind) { - builder.addAttribute(Attribute::DeadOnUnwind); + builder.addAttribute(llvm::Attribute::DeadOnUnwind); } - if (attributes.in_alloca) + if (attributes->in_alloca) { __builtin_trap(); // TODO } - if (attributes.dereferenceable) + if (attributes->dereferenceable) { - builder.addDereferenceableAttr(attributes.dereferenceable_bytes); + builder.addDereferenceableAttr(attributes->dereferenceable_bytes); } - if (attributes.dereferenceable_or_null) + if (attributes->dereferenceable_or_null) { - builder.addDereferenceableOrNullAttr(attributes.dereferenceable_bytes); + builder.addDereferenceableOrNullAttr(attributes->dereferenceable_bytes); } - if (attributes.nest) + if (attributes->nest) { - builder.addAttribute(Attribute::Nest); + builder.addAttribute(llvm::Attribute::Nest); } - if (attributes.by_value) + if (attributes->by_value) { - builder.addByValAttr(attributes.semantic_type); + builder.addByValAttr(llvm::unwrap(attributes->semantic_type)); } - if (attributes.by_reference) + if (attributes->by_reference) { - builder.addByRefAttr(attributes.semantic_type); + builder.addByRefAttr(llvm::unwrap(attributes->semantic_type)); } - if (attributes.no_capture) + if (attributes->no_capture) { - builder.addAttribute(Attribute::NoCapture); + builder.addAttribute(llvm::Attribute::NoCapture); } - auto attribute_set = AttributeSet::get(context, builder); + auto attribute_set = llvm::AttributeSet::get(*llvm::unwrap(context), builder); return attribute_set; } -struct BBLLVMFunctionAttributesFlags0 +inline fn BBLLVMAttributeList llvm_attribute_list_to_abi(llvm::AttributeList list) { - u64 noreturn:1; - u64 cmse_ns_call:1; - u64 nounwind:1; - u64 returns_twice:1; - u64 cold:1; - u64 hot:1; - u64 no_duplicate:1; - u64 convergent:1; - u64 no_merge:1; - u64 will_return:1; - u64 no_caller_saved_registers:1; - u64 no_cf_check:1; - u64 no_callback:1; - u64 alloc_size:1; - u64 uniform_work_group_size:1; - u64 aarch64_pstate_sm_body:1; - u64 aarch64_pstate_sm_enabled:1; - u64 aarch64_pstate_sm_compatible:1; - u64 aarch64_preserves_za:1; - u64 aarch64_in_za:1; - u64 aarch64_out_za:1; - u64 aarch64_inout_za:1; - u64 aarch64_preserves_zt0:1; - u64 aarch64_in_zt0:1; - u64 aarch64_out_zt0:1; - u64 aarch64_inout_zt0:1; - u64 optimize_for_size:1; - u64 min_size:1; - u64 no_red_zone:1; - u64 indirect_tls_seg_refs:1; - u64 no_implicit_floats:1; - u64 sample_profile_suffix_elision_policy:1; - u64 memory_none:1; - u64 memory_readonly:1; - u64 memory_inaccessible_or_arg_memory_only:1; - u64 memory_arg_memory_only:1; - u64 strict_fp:1; - u64 no_inline:1; - u64 always_inline:1; - u64 guard_no_cf:1; + static_assert(sizeof(llvm::AttributeList) == sizeof(uintptr_t)); + static_assert(sizeof(BBLLVMAttributeList) == sizeof(uintptr_t)); - // TODO: branch protection function attributes - // TODO: cpu features + return list.getRawPointer(); +} - // Call-site begin - u64 call_no_builtins:1; - - u64 definition_frame_pointer_kind:2; - u64 definition_less_precise_fpmad:1; - u64 definition_null_pointer_is_valid:1; - u64 definition_no_trapping_fp_math:1; - u64 definition_no_infs_fp_math:1; - u64 definition_no_nans_fp_math:1; - u64 definition_approx_func_fp_math:1; - u64 definition_unsafe_fp_math:1; - u64 definition_use_soft_float:1; - u64 definition_no_signed_zeroes_fp_math:1; - u64 definition_stack_realignment:1; - u64 definition_backchain:1; - u64 definition_split_stack:1; - u64 definition_speculative_load_hardening:1; - u64 definition_zero_call_used_registers:4; - // TODO: denormal builtins - u64 definition_non_lazy_bind:1; - u64 definition_cmse_nonsecure_entry:1; - u64 definition_unwind_table_kind:2; -}; - -static_assert(sizeof(BBLLVMFunctionAttributesFlags0) == sizeof(u64)); - -struct BBLLVMFunctionAttributesFlags1 +inline fn llvm::AttributeList abi_attribute_list_to_llvm(BBLLVMAttributeList list) { - u64 definition_disable_tail_calls:1; - u64 definition_stack_protect_strong:1; - u64 definition_stack_protect:1; - u64 definition_stack_protect_req:1; - u64 definition_aarch64_new_za:1; - u64 definition_aarch64_new_zt0:1; - u64 definition_optimize_none:1; - u64 definition_naked:1; - u64 definition_inline_hint:1; - u64 _:55; -}; + static_assert(sizeof(llvm::AttributeList) == sizeof(uintptr_t)); + static_assert(sizeof(BBLLVMAttributeList) == sizeof(uintptr_t)); + auto attribute_list = *(llvm::AttributeList*)&list; + return attribute_list; +} -static_assert(sizeof(BBLLVMFunctionAttributesFlags1) == sizeof(u64)); - -struct BBLLVMFunctionAttributes +EXPORT BBLLVMAttributeList llvm_attribute_list_build(LLVMContextRef context, BBLLVMAttributeListOptions* attributes, bool call_site) { - String prefer_vector_width; - String stack_protector_buffer_size; - String definition_probe_stack; - String definition_stack_probe_size; + llvm::AttrBuilder function_attribute_builder(*llvm::unwrap(context)); - BBLLVMFunctionAttributesFlags0 flags0; - BBLLVMFunctionAttributesFlags1 flags1; -}; - -static_assert(sizeof(BBLLVMFunctionAttributes) == 10 * sizeof(u64)); - -struct BBLLVMAttributeList -{ - BBLLVMFunctionAttributes function; - BBLLVMArgumentAttributes return_; - const BBLLVMArgumentAttributes* argument_pointer; - u64 argument_count; -}; - -static_assert(sizeof(BBLLVMAttributeList) == sizeof(BBLLVMFunctionAttributes) + sizeof(BBLLVMArgumentAttributes) + sizeof(void*) + sizeof(u64)); - -typedef void* BBLLVMAttributeListHandle; - -EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context, const BBLLVMAttributeList& attributes, bool call_site) -{ - AttrBuilder function_attribute_builder(context); - - if (attributes.function.prefer_vector_width.length) + if (attributes->function.prefer_vector_width.length) { - function_attribute_builder.addAttribute("prefer-vector-width", string_ref(attributes.function.prefer_vector_width)); + function_attribute_builder.addAttribute("prefer-vector-width", string_ref(attributes->function.prefer_vector_width)); } - if (attributes.function.stack_protector_buffer_size.length) + if (attributes->function.stack_protector_buffer_size.length) { - function_attribute_builder.addAttribute("stack-protector-buffer-size", string_ref(attributes.function.stack_protector_buffer_size)); + function_attribute_builder.addAttribute("stack-protector-buffer-size", string_ref(attributes->function.stack_protector_buffer_size)); } - if (attributes.function.flags0.noreturn) + if (attributes->function.flags0.noreturn) { - function_attribute_builder.addAttribute(Attribute::NoReturn); + function_attribute_builder.addAttribute(llvm::Attribute::NoReturn); } - if (attributes.function.flags0.cmse_ns_call) + if (attributes->function.flags0.cmse_ns_call) { function_attribute_builder.addAttribute("cmse_nonsecure_call"); } - if (attributes.function.flags0.nounwind) + if (attributes->function.flags0.nounwind) { - function_attribute_builder.addAttribute(Attribute::NoUnwind); + function_attribute_builder.addAttribute(llvm::Attribute::NoUnwind); } - if (attributes.function.flags0.returns_twice) + if (attributes->function.flags0.returns_twice) { - function_attribute_builder.addAttribute(Attribute::ReturnsTwice); + function_attribute_builder.addAttribute(llvm::Attribute::ReturnsTwice); } - if (attributes.function.flags0.cold) + if (attributes->function.flags0.cold) { - function_attribute_builder.addAttribute(Attribute::Cold); + function_attribute_builder.addAttribute(llvm::Attribute::Cold); } - if (attributes.function.flags0.hot) + if (attributes->function.flags0.hot) { - function_attribute_builder.addAttribute(Attribute::Hot); + function_attribute_builder.addAttribute(llvm::Attribute::Hot); } - if (attributes.function.flags0.no_duplicate) + if (attributes->function.flags0.no_duplicate) { - function_attribute_builder.addAttribute(Attribute::NoDuplicate); + function_attribute_builder.addAttribute(llvm::Attribute::NoDuplicate); } - if (attributes.function.flags0.convergent) + if (attributes->function.flags0.convergent) { - function_attribute_builder.addAttribute(Attribute::Convergent); + function_attribute_builder.addAttribute(llvm::Attribute::Convergent); } - if (attributes.function.flags0.no_merge) + if (attributes->function.flags0.no_merge) { - function_attribute_builder.addAttribute(Attribute::NoMerge); + function_attribute_builder.addAttribute(llvm::Attribute::NoMerge); } - if (attributes.function.flags0.will_return) + if (attributes->function.flags0.will_return) { - function_attribute_builder.addAttribute(Attribute::WillReturn); + function_attribute_builder.addAttribute(llvm::Attribute::WillReturn); } - if (attributes.function.flags0.no_caller_saved_registers) + if (attributes->function.flags0.no_caller_saved_registers) { function_attribute_builder.addAttribute("no-caller-saved-registers"); } - if (attributes.function.flags0.no_cf_check) + if (attributes->function.flags0.no_cf_check) { - function_attribute_builder.addAttribute(Attribute::NoCfCheck); + function_attribute_builder.addAttribute(llvm::Attribute::NoCfCheck); } - if (attributes.function.flags0.no_callback) + if (attributes->function.flags0.no_callback) { - function_attribute_builder.addAttribute(Attribute::NoCallback); + function_attribute_builder.addAttribute(llvm::Attribute::NoCallback); } - if (attributes.function.flags0.alloc_size) + if (attributes->function.flags0.alloc_size) { __builtin_trap(); // TODO } - if (attributes.function.flags0.uniform_work_group_size) + if (attributes->function.flags0.uniform_work_group_size) { __builtin_trap(); // TODO } - if (attributes.function.flags0.aarch64_pstate_sm_body) + if (attributes->function.flags0.aarch64_pstate_sm_body) { function_attribute_builder.addAttribute("aarch64_pstate_sm_body"); } - if (attributes.function.flags0.aarch64_pstate_sm_enabled) + if (attributes->function.flags0.aarch64_pstate_sm_enabled) { function_attribute_builder.addAttribute("aarch64_pstate_sm_enabled"); } - if (attributes.function.flags0.aarch64_pstate_sm_compatible) + if (attributes->function.flags0.aarch64_pstate_sm_compatible) { function_attribute_builder.addAttribute("aarch64_pstate_sm_compatible"); } - if (attributes.function.flags0.aarch64_preserves_za) + if (attributes->function.flags0.aarch64_preserves_za) { function_attribute_builder.addAttribute("aarch64_preserves_za"); } - if (attributes.function.flags0.aarch64_in_za) + if (attributes->function.flags0.aarch64_in_za) { function_attribute_builder.addAttribute("aarch64_in_za"); } - if (attributes.function.flags0.aarch64_out_za) + if (attributes->function.flags0.aarch64_out_za) { function_attribute_builder.addAttribute("aarch64_out_za"); } - if (attributes.function.flags0.aarch64_inout_za) + if (attributes->function.flags0.aarch64_inout_za) { function_attribute_builder.addAttribute("aarch64_inout_za"); } - if (attributes.function.flags0.aarch64_preserves_zt0) + if (attributes->function.flags0.aarch64_preserves_zt0) { function_attribute_builder.addAttribute("aarch64_preserves_zt0"); } - if (attributes.function.flags0.aarch64_in_zt0) + if (attributes->function.flags0.aarch64_in_zt0) { function_attribute_builder.addAttribute("aarch64_in_zt0"); } - if (attributes.function.flags0.aarch64_out_zt0) + if (attributes->function.flags0.aarch64_out_zt0) { function_attribute_builder.addAttribute("aarch64_out_zt0"); } - if (attributes.function.flags0.aarch64_inout_zt0) + if (attributes->function.flags0.aarch64_inout_zt0) { function_attribute_builder.addAttribute("aarch64_inout_zt0"); } - if (attributes.function.flags0.optimize_for_size) + if (attributes->function.flags0.optimize_for_size) { - function_attribute_builder.addAttribute(Attribute::OptimizeForSize); + function_attribute_builder.addAttribute(llvm::Attribute::OptimizeForSize); } - if (attributes.function.flags0.min_size) + if (attributes->function.flags0.min_size) { - function_attribute_builder.addAttribute(Attribute::MinSize); + function_attribute_builder.addAttribute(llvm::Attribute::MinSize); } - if (attributes.function.flags0.no_red_zone) + if (attributes->function.flags0.no_red_zone) { - function_attribute_builder.addAttribute(Attribute::NoRedZone); + function_attribute_builder.addAttribute(llvm::Attribute::NoRedZone); } - if (attributes.function.flags0.indirect_tls_seg_refs) + if (attributes->function.flags0.indirect_tls_seg_refs) { function_attribute_builder.addAttribute("indirect-tls-seg-refs"); } - if (attributes.function.flags0.no_implicit_floats) + if (attributes->function.flags0.no_implicit_floats) { - function_attribute_builder.addAttribute(Attribute::NoImplicitFloat); + function_attribute_builder.addAttribute(llvm::Attribute::NoImplicitFloat); } - if (attributes.function.flags0.sample_profile_suffix_elision_policy) + if (attributes->function.flags0.sample_profile_suffix_elision_policy) { function_attribute_builder.addAttribute("sample-profile-suffix-elision-policy", "selected"); } - if (attributes.function.flags0.memory_none) + if (attributes->function.flags0.memory_none) { function_attribute_builder.addMemoryAttr(llvm::MemoryEffects::none()); } - if (attributes.function.flags0.memory_readonly) + if (attributes->function.flags0.memory_readonly) { function_attribute_builder.addMemoryAttr(llvm::MemoryEffects::readOnly()); } - if (attributes.function.flags0.memory_inaccessible_or_arg_memory_only) + if (attributes->function.flags0.memory_inaccessible_or_arg_memory_only) { function_attribute_builder.addMemoryAttr(llvm::MemoryEffects::inaccessibleOrArgMemOnly()); } - if (attributes.function.flags0.memory_arg_memory_only) + if (attributes->function.flags0.memory_arg_memory_only) { - Attribute attribute = function_attribute_builder.getAttribute(Attribute::Memory); + llvm::Attribute attribute = function_attribute_builder.getAttribute(llvm::Attribute::Memory); function_attribute_builder.addMemoryAttr(attribute.getMemoryEffects() | llvm::MemoryEffects::argMemOnly()); } @@ -711,25 +597,25 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context, if (call_site) { - if (attributes.function.flags0.call_no_builtins) + if (attributes->function.flags0.call_no_builtins) { - function_attribute_builder.addAttribute(Attribute::NoBuiltin); + function_attribute_builder.addAttribute(llvm::Attribute::NoBuiltin); } } else { - if (attributes.function.definition_probe_stack.length) + if (attributes->function.definition_probe_stack.length) { - function_attribute_builder.addAttribute("probe-stack", string_ref(attributes.function.definition_probe_stack)); + function_attribute_builder.addAttribute("probe-stack", string_ref(attributes->function.definition_probe_stack)); } - if (attributes.function.definition_stack_probe_size.length) + if (attributes->function.definition_stack_probe_size.length) { - function_attribute_builder.addAttribute("stack-probe-size", string_ref(attributes.function.definition_stack_probe_size)); + function_attribute_builder.addAttribute("stack-probe-size", string_ref(attributes->function.definition_stack_probe_size)); } - StringRef frame_pointer_kind_name; - switch ((BBLLVMAttributeFramePointerKind) attributes.function.flags0.definition_frame_pointer_kind) + llvm::StringRef frame_pointer_kind_name; + switch ((BBLLVMAttributeFramePointerKind) attributes->function.flags0.definition_frame_pointer_kind) { case BBLLVMAttributeFramePointerKind::None: frame_pointer_kind_name = "none"; break; case BBLLVMAttributeFramePointerKind::Reserved: frame_pointer_kind_name = "reserved"; break; @@ -738,184 +624,183 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context, } function_attribute_builder.addAttribute("frame-pointer", frame_pointer_kind_name); - if (attributes.function.flags0.definition_less_precise_fpmad) + if (attributes->function.flags0.definition_less_precise_fpmad) { function_attribute_builder.addAttribute("less-precise-fp-mad", "true"); } - if (attributes.function.flags0.definition_null_pointer_is_valid) + if (attributes->function.flags0.definition_null_pointer_is_valid) { - function_attribute_builder.addAttribute(Attribute::NullPointerIsValid); + function_attribute_builder.addAttribute(llvm::Attribute::NullPointerIsValid); } - if (attributes.function.flags0.definition_no_trapping_fp_math) + if (attributes->function.flags0.definition_no_trapping_fp_math) { function_attribute_builder.addAttribute("no-trapping-math", "true"); } - if (attributes.function.flags0.definition_no_infs_fp_math) + if (attributes->function.flags0.definition_no_infs_fp_math) { function_attribute_builder.addAttribute("no-infs-fp-math", "true"); } - if (attributes.function.flags0.definition_no_nans_fp_math) + if (attributes->function.flags0.definition_no_nans_fp_math) { function_attribute_builder.addAttribute("no-nans-fp-math", "true"); } - if (attributes.function.flags0.definition_approx_func_fp_math) + if (attributes->function.flags0.definition_approx_func_fp_math) { function_attribute_builder.addAttribute("approx-func-fp-math", "true"); } - if (attributes.function.flags0.definition_unsafe_fp_math) + if (attributes->function.flags0.definition_unsafe_fp_math) { function_attribute_builder.addAttribute("unsafe-fp-math", "true"); } - if (attributes.function.flags0.definition_use_soft_float) + if (attributes->function.flags0.definition_use_soft_float) { function_attribute_builder.addAttribute("use-soft-float", "true"); } - if (attributes.function.flags0.definition_no_signed_zeroes_fp_math) + if (attributes->function.flags0.definition_no_signed_zeroes_fp_math) { function_attribute_builder.addAttribute("no-signed-zeros-fp-math", "true"); } - if (attributes.function.flags0.definition_stack_realignment) + if (attributes->function.flags0.definition_stack_realignment) { function_attribute_builder.addAttribute("stackrealign"); } - if (attributes.function.flags0.definition_backchain) + if (attributes->function.flags0.definition_backchain) { function_attribute_builder.addAttribute("backchain"); } - if (attributes.function.flags0.definition_split_stack) + if (attributes->function.flags0.definition_split_stack) { function_attribute_builder.addAttribute("split-stack"); } - if (attributes.function.flags0.definition_speculative_load_hardening) + if (attributes->function.flags0.definition_speculative_load_hardening) { function_attribute_builder.addAttribute("split-stack"); } - if (attributes.function.flags0.definition_zero_call_used_registers) + if (attributes->function.flags0.definition_zero_call_used_registers != ZeroCallUsedRegsKind::all) { __builtin_trap(); // TODO } // TODO: denormal builtins - if (attributes.function.flags0.definition_non_lazy_bind) + if (attributes->function.flags0.definition_non_lazy_bind) { - function_attribute_builder.addAttribute(Attribute::NonLazyBind); + function_attribute_builder.addAttribute(llvm::Attribute::NonLazyBind); } - if (attributes.function.flags0.definition_cmse_nonsecure_entry) + if (attributes->function.flags0.definition_cmse_nonsecure_entry) { function_attribute_builder.addAttribute("cmse_nonsecure_entry"); } - UWTableKind unwind_table_kind; - switch ((BBLLVMUWTableKind)attributes.function.flags0.definition_unwind_table_kind) + llvm::UWTableKind unwind_table_kind; + switch ((BBLLVMUWTableKind)attributes->function.flags0.definition_unwind_table_kind) { - case BBLLVMUWTableKind::None: unwind_table_kind = UWTableKind::None; break; - case BBLLVMUWTableKind::Sync: unwind_table_kind = UWTableKind::Sync; break; - case BBLLVMUWTableKind::Async: unwind_table_kind = UWTableKind::Async; break; + case BBLLVMUWTableKind::None: unwind_table_kind = llvm::UWTableKind::None; break; + case BBLLVMUWTableKind::Sync: unwind_table_kind = llvm::UWTableKind::Sync; break; + case BBLLVMUWTableKind::Async: unwind_table_kind = llvm::UWTableKind::Async; break; } function_attribute_builder.addUWTableAttr(unwind_table_kind); - if (attributes.function.flags1.definition_disable_tail_calls) + if (attributes->function.flags1.definition_disable_tail_calls) { function_attribute_builder.addAttribute("disable-tail-calls", "true"); } - if (attributes.function.flags1.definition_stack_protect_strong) + if (attributes->function.flags1.definition_stack_protect_strong) { - function_attribute_builder.addAttribute(Attribute::StackProtectStrong); + function_attribute_builder.addAttribute(llvm::Attribute::StackProtectStrong); } - if (attributes.function.flags1.definition_stack_protect) + if (attributes->function.flags1.definition_stack_protect) { - function_attribute_builder.addAttribute(Attribute::StackProtect); + function_attribute_builder.addAttribute(llvm::Attribute::StackProtect); } - if (attributes.function.flags1.definition_stack_protect_req) + if (attributes->function.flags1.definition_stack_protect_req) { - function_attribute_builder.addAttribute(Attribute::StackProtectReq); + function_attribute_builder.addAttribute(llvm::Attribute::StackProtectReq); } - if (attributes.function.flags1.definition_aarch64_new_za) + if (attributes->function.flags1.definition_aarch64_new_za) { function_attribute_builder.addAttribute("aarch64_new_za"); } - if (attributes.function.flags1.definition_aarch64_new_zt0) + if (attributes->function.flags1.definition_aarch64_new_zt0) { function_attribute_builder.addAttribute("aarch64_new_zt0"); } - if (attributes.function.flags1.definition_optimize_none) + if (attributes->function.flags1.definition_optimize_none) { - function_attribute_builder.addAttribute(Attribute::OptimizeNone); + function_attribute_builder.addAttribute(llvm::Attribute::OptimizeNone); } - if (attributes.function.flags1.definition_naked) + if (attributes->function.flags1.definition_naked) { - function_attribute_builder.addAttribute(Attribute::Naked); + function_attribute_builder.addAttribute(llvm::Attribute::Naked); } - if (attributes.function.flags1.definition_inline_hint) + if (attributes->function.flags1.definition_inline_hint) { - function_attribute_builder.addAttribute(Attribute::InlineHint); + function_attribute_builder.addAttribute(llvm::Attribute::InlineHint); } } - auto function_attributes = AttributeSet::get(context, function_attribute_builder); + auto function_attributes = llvm::AttributeSet::get(*llvm::unwrap(context), function_attribute_builder); - auto return_attributes = build_argument_attributes(context, attributes.return_); + auto return_attributes = build_argument_attributes(context, &attributes->return_); - AttributeSet argument_attribute_buffer[128]; - assert(attributes.argument_count < array_length(argument_attribute_buffer)); + llvm::AttributeSet argument_attribute_buffer[128]; + assert(attributes->argument_count < array_length(argument_attribute_buffer)); - for (u64 i = 0; i < attributes.argument_count; i += 1) + for (u64 i = 0; i < attributes->argument_count; i += 1) { - auto attribute_set = build_argument_attributes(context, attributes.argument_pointer[i]); + auto attribute_set = build_argument_attributes(context, &attributes->argument_pointer[i]); argument_attribute_buffer[i] = attribute_set; } - ArrayRef argument_attributes = ArrayRef(argument_attribute_buffer, attributes.argument_count); + llvm::ArrayRef argument_attributes = llvm::ArrayRef(argument_attribute_buffer, attributes->argument_count); - auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, argument_attributes); + auto attribute_list = llvm::AttributeList::get(*llvm::unwrap(context), function_attributes, return_attributes, argument_attributes); - static_assert(sizeof(AttributeList) == sizeof(uintptr_t)); - - return *(BBLLVMAttributeListHandle*)&attribute_list; + return llvm_attribute_list_to_abi(attribute_list); } -EXPORT bool llvm_instruction_is_call_base(Instruction* instruction) +EXPORT bool llvm_instruction_is_call_base(llvm::Instruction* instruction) { - return isa(instruction); + return isa(instruction); } -EXPORT void llvm_function_set_attributes(Function& function, BBLLVMAttributeListHandle attribute_list_handle) +EXPORT void llvm_function_set_attributes(LLVMValueRef f, BBLLVMAttributeList attribute_list_handle) { - auto attribute_list = *(AttributeList*)&attribute_list_handle; - function.setAttributes(attribute_list); + auto* function = llvm::unwrap(f); + auto attribute_list = abi_attribute_list_to_llvm(attribute_list_handle); + function->setAttributes(attribute_list); } -EXPORT void llvm_call_base_set_attributes(CallBase& call, BBLLVMAttributeListHandle attribute_list_handle) +EXPORT void llvm_call_base_set_attributes(llvm::CallBase* call, BBLLVMAttributeList attribute_list_handle) { - auto attribute_list = *(AttributeList*)&attribute_list_handle; - call.setAttributes(attribute_list); + auto attribute_list = abi_attribute_list_to_llvm(attribute_list_handle); + call->setAttributes(attribute_list); } -fn String stream_to_string(raw_string_ostream& stream) +fn String stream_to_string(llvm::raw_string_ostream& stream) { // No need to call stream.flush(); because it's string-based stream.flush(); @@ -933,21 +818,22 @@ fn String stream_to_string(raw_string_ostream& stream) return String{ result, length }; } -EXPORT String llvm_function_to_string(Function& function) +EXPORT String llvm_function_to_string(llvm::Function& function) { std::string buffer; - raw_string_ostream os(buffer); + llvm::raw_string_ostream os(buffer); function.print(os); os.flush(); auto result = stream_to_string(os); return result; } -EXPORT bool llvm_function_verify(Function& function, String* error_message) +EXPORT bool llvm_function_verify(LLVMValueRef function_value, String* error_message) { std::string message_buffer; - raw_string_ostream message_stream(message_buffer); + llvm::raw_string_ostream message_stream(message_buffer); + auto& function = *llvm::unwrap(function_value); bool result = verifyFunction(function, &message_stream); auto size = message_stream.str().size(); *error_message = stream_to_string(message_stream); @@ -956,23 +842,24 @@ EXPORT bool llvm_function_verify(Function& function, String* error_message) return !result; } -EXPORT bool llvm_module_verify(const Module& module, String* error_message) +EXPORT bool llvm_module_verify(LLVMModuleRef m, String* error_message) { std::string message_buffer; - raw_string_ostream message_stream(message_buffer); + llvm::raw_string_ostream message_stream(message_buffer); - bool result = verifyModule(module, &message_stream); + const auto& module = *llvm::unwrap(m); + bool result = llvm::verifyModule(module, &message_stream); *error_message = stream_to_string(message_stream); // We invert the condition because LLVM conventions are just stupid return !result; } -EXPORT String llvm_module_to_string(Module* module) +EXPORT String llvm_module_to_string(LLVMModuleRef module) { std::string buffer; - raw_string_ostream stream(buffer); - module->print(stream, 0); + llvm::raw_string_ostream stream(buffer); + llvm::unwrap(module)->print(stream, 0); return stream_to_string(stream); } @@ -1000,9 +887,9 @@ EXPORT String llvm_host_cpu_name() EXPORT String llvm_host_cpu_features() { - SubtargetFeatures Features; + llvm::SubtargetFeatures Features; #if LLVM_VERSION_MAJOR >= 19 - auto host_cpu_features = sys::getHostCPUFeatures(); + auto host_cpu_features = llvm::sys::getHostCPUFeatures(); #else StringMap host_cpu_features; if (!sys::getHostCPUFeatures(host_cpu_features)) { @@ -1279,50 +1166,50 @@ struct BBLLVMTargetMachineCreate static_assert(sizeof(BBLLVMTargetMachineCreate) == 192); static_assert(BB_LLVM_TARGET_MACHINE_CREATE_PADDING_BYTE_COUNT == 4); -EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate& create, String* error_message) +EXPORT llvm::TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate& create, String* error_message) { std::string error_message_string; - const Target* target = TargetRegistry::lookupTarget(string_ref(create.target_triple), error_message_string); + const llvm::Target* target = llvm::TargetRegistry::lookupTarget(string_ref(create.target_triple), error_message_string); - TargetMachine* target_machine; + llvm::TargetMachine* target_machine; if (target) { - std::optional code_model; + std::optional code_model; switch (create.code_model) { case BBLLVMCodeModel::none: code_model = std::nullopt; break; - case BBLLVMCodeModel::tiny: code_model = CodeModel::Tiny; break; - case BBLLVMCodeModel::small: code_model = CodeModel::Small; break; - case BBLLVMCodeModel::kernel: code_model = CodeModel::Kernel; break; - case BBLLVMCodeModel::medium: code_model = CodeModel::Medium; break; - case BBLLVMCodeModel::large: code_model = CodeModel::Large; break; + case BBLLVMCodeModel::tiny: code_model = llvm::CodeModel::Tiny; break; + case BBLLVMCodeModel::small: code_model = llvm::CodeModel::Small; break; + case BBLLVMCodeModel::kernel: code_model = llvm::CodeModel::Kernel; break; + case BBLLVMCodeModel::medium: code_model = llvm::CodeModel::Medium; break; + case BBLLVMCodeModel::large: code_model = llvm::CodeModel::Large; break; } - std::optional relocation_model; + std::optional relocation_model; switch (create.relocation_model) { case BBLLVMRelocationModel::default_relocation: relocation_model = std::nullopt; break; - case BBLLVMRelocationModel::static_relocation: relocation_model = Reloc::Static; break; - case BBLLVMRelocationModel::pic: relocation_model = Reloc::PIC_; break; - case BBLLVMRelocationModel::dynamic_no_pic: relocation_model = Reloc::DynamicNoPIC; break; - case BBLLVMRelocationModel::ropi: relocation_model = Reloc::ROPI; break; - case BBLLVMRelocationModel::rwpi: relocation_model = Reloc::RWPI; break; - case BBLLVMRelocationModel::ropi_rwpi: relocation_model = Reloc::ROPI_RWPI; break; + case BBLLVMRelocationModel::static_relocation: relocation_model = llvm::Reloc::Static; break; + case BBLLVMRelocationModel::pic: relocation_model = llvm::Reloc::PIC_; break; + case BBLLVMRelocationModel::dynamic_no_pic: relocation_model = llvm::Reloc::DynamicNoPIC; break; + case BBLLVMRelocationModel::ropi: relocation_model = llvm::Reloc::ROPI; break; + case BBLLVMRelocationModel::rwpi: relocation_model = llvm::Reloc::RWPI; break; + case BBLLVMRelocationModel::ropi_rwpi: relocation_model = llvm::Reloc::ROPI_RWPI; break; } - CodeGenOptLevel optimization_level; + llvm::CodeGenOptLevel optimization_level; switch (create.optimization_level) { - case BBLLVMCodeGenerationOptimizationLevel::none: optimization_level = CodeGenOptLevel::None; break; - case BBLLVMCodeGenerationOptimizationLevel::less: optimization_level = CodeGenOptLevel::Less; break; - case BBLLVMCodeGenerationOptimizationLevel::normal: optimization_level = CodeGenOptLevel::Default; break; - case BBLLVMCodeGenerationOptimizationLevel::aggressive: optimization_level = CodeGenOptLevel::Aggressive; break; + case BBLLVMCodeGenerationOptimizationLevel::none: optimization_level = llvm::CodeGenOptLevel::None; break; + case BBLLVMCodeGenerationOptimizationLevel::less: optimization_level = llvm::CodeGenOptLevel::Less; break; + case BBLLVMCodeGenerationOptimizationLevel::normal: optimization_level = llvm::CodeGenOptLevel::Default; break; + case BBLLVMCodeGenerationOptimizationLevel::aggressive: optimization_level = llvm::CodeGenOptLevel::Aggressive; break; } // INFO: This calls the default constructor, so all LLVM defaults are set and we only override what we control - TargetOptions target_options; + llvm::TargetOptions target_options; target_options.UnsafeFPMath = create.target_options.unsafe_fp_math; target_options.NoInfsFPMath = create.target_options.no_infs_fp_math; @@ -1341,16 +1228,16 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate auto global_isel_abort_mode = (BBLLVMGlobalISelAbortMode)create.target_options.global_isel_abort_mode; switch (global_isel_abort_mode) { - case BBLLVMGlobalISelAbortMode::disable: target_options.GlobalISelAbort = GlobalISelAbortMode::Disable; break; - case BBLLVMGlobalISelAbortMode::enable: target_options.GlobalISelAbort = GlobalISelAbortMode::Enable; break; - case BBLLVMGlobalISelAbortMode::disable_with_diag: target_options.GlobalISelAbort = GlobalISelAbortMode::DisableWithDiag; break; + case BBLLVMGlobalISelAbortMode::disable: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::Disable; break; + case BBLLVMGlobalISelAbortMode::enable: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::Enable; break; + case BBLLVMGlobalISelAbortMode::disable_with_diag: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::DisableWithDiag; break; } auto swift_async_frame_pointer = (BBLLVMSwiftAsyncFramePointerMode)create.target_options.swift_async_frame_pointer; switch (swift_async_frame_pointer) { - case BBLLVMSwiftAsyncFramePointerMode::deployment_based: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::DeploymentBased; break; - case BBLLVMSwiftAsyncFramePointerMode::always: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Always; break; - case BBLLVMSwiftAsyncFramePointerMode::never: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Never; break; + case BBLLVMSwiftAsyncFramePointerMode::deployment_based: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::DeploymentBased; break; + case BBLLVMSwiftAsyncFramePointerMode::always: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::Always; break; + case BBLLVMSwiftAsyncFramePointerMode::never: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::Never; break; } target_options.UseInitArray = create.target_options.use_init_array; @@ -1382,10 +1269,10 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate auto bb_sections = (BBLLVMBasicBlockSection) create.target_options.bb_sections; switch (bb_sections) { - case BBLLVMBasicBlockSection::all: target_options.BBSections = BasicBlockSection::All; break; - case BBLLVMBasicBlockSection::list: target_options.BBSections = BasicBlockSection::List; break; - case BBLLVMBasicBlockSection::preset: target_options.BBSections = BasicBlockSection::Preset; break; - case BBLLVMBasicBlockSection::none: target_options.BBSections = BasicBlockSection::None; break; + case BBLLVMBasicBlockSection::all: target_options.BBSections = llvm::BasicBlockSection::All; break; + case BBLLVMBasicBlockSection::list: target_options.BBSections = llvm::BasicBlockSection::List; break; + case BBLLVMBasicBlockSection::preset: target_options.BBSections = llvm::BasicBlockSection::Preset; break; + case BBLLVMBasicBlockSection::none: target_options.BBSections = llvm::BasicBlockSection::None; break; } target_options.EmitCallSiteInfo = create.target_options.emit_call_site_information; @@ -1405,57 +1292,57 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate auto float_abi = (BBLLVMFloatAbi) create.target_options.float_abi; switch (float_abi) { - case BBLLVMFloatAbi::normal: target_options.FloatABIType = FloatABI::Default; break; - case BBLLVMFloatAbi::soft: target_options.FloatABIType = FloatABI::Soft; break; - case BBLLVMFloatAbi::hard: target_options.FloatABIType = FloatABI::Hard; break; + case BBLLVMFloatAbi::normal: target_options.FloatABIType = llvm::FloatABI::Default; break; + case BBLLVMFloatAbi::soft: target_options.FloatABIType = llvm::FloatABI::Soft; break; + case BBLLVMFloatAbi::hard: target_options.FloatABIType = llvm::FloatABI::Hard; break; } auto thread_model = (BBLLVMThreadModel) create.target_options.thread_model; switch (thread_model) { - case BBLLVMThreadModel::posix: target_options.ThreadModel = ThreadModel::POSIX; break; - case BBLLVMThreadModel::single: target_options.ThreadModel = ThreadModel::Single; break; + case BBLLVMThreadModel::posix: target_options.ThreadModel = llvm::ThreadModel::POSIX; break; + case BBLLVMThreadModel::single: target_options.ThreadModel = llvm::ThreadModel::Single; break; } auto fp_op_fusion_mode = (BBLLVMFPOpFusion) create.target_options.fp_op_fusion_mode; switch (fp_op_fusion_mode) { - case BBLLVMFPOpFusion::fast: target_options.AllowFPOpFusion = FPOpFusion::Fast; break; - case BBLLVMFPOpFusion::standard: target_options.AllowFPOpFusion = FPOpFusion::Standard; break; - case BBLLVMFPOpFusion::strict: target_options.AllowFPOpFusion = FPOpFusion::Strict; break; + case BBLLVMFPOpFusion::fast: target_options.AllowFPOpFusion = llvm::FPOpFusion::Fast; break; + case BBLLVMFPOpFusion::standard: target_options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break; + case BBLLVMFPOpFusion::strict: target_options.AllowFPOpFusion = llvm::FPOpFusion::Strict; break; } auto eabi_version = (BBLLVMEAbi) create.target_options.eabi_version; switch (eabi_version) { - case BBLLVMEAbi::unknown: target_options.EABIVersion = EABI::Unknown; break; - case BBLLVMEAbi::normal: target_options.EABIVersion = EABI::Default; break; - case BBLLVMEAbi::eabi4: target_options.EABIVersion = EABI::EABI4; break; - case BBLLVMEAbi::eabi5: target_options.EABIVersion = EABI::EABI5; break; - case BBLLVMEAbi::gnu: target_options.EABIVersion = EABI::GNU; break; + case BBLLVMEAbi::unknown: target_options.EABIVersion = llvm::EABI::Unknown; break; + case BBLLVMEAbi::normal: target_options.EABIVersion = llvm::EABI::Default; break; + case BBLLVMEAbi::eabi4: target_options.EABIVersion = llvm::EABI::EABI4; break; + case BBLLVMEAbi::eabi5: target_options.EABIVersion = llvm::EABI::EABI5; break; + case BBLLVMEAbi::gnu: target_options.EABIVersion = llvm::EABI::GNU; break; } auto debugger_kind = (BBLLVMDebuggerKind) create.target_options.debugger_kind; switch (debugger_kind) { - case BBLLVMDebuggerKind::normal: target_options.DebuggerTuning = DebuggerKind::Default; break; - case BBLLVMDebuggerKind::gdb: target_options.DebuggerTuning = DebuggerKind::GDB; break; - case BBLLVMDebuggerKind::lldb: target_options.DebuggerTuning = DebuggerKind::LLDB; break; - case BBLLVMDebuggerKind::sce: target_options.DebuggerTuning = DebuggerKind::SCE; break; - case BBLLVMDebuggerKind::dbx: target_options.DebuggerTuning = DebuggerKind::DBX; break; + case BBLLVMDebuggerKind::normal: target_options.DebuggerTuning = llvm::DebuggerKind::Default; break; + case BBLLVMDebuggerKind::gdb: target_options.DebuggerTuning = llvm::DebuggerKind::GDB; break; + case BBLLVMDebuggerKind::lldb: target_options.DebuggerTuning = llvm::DebuggerKind::LLDB; break; + case BBLLVMDebuggerKind::sce: target_options.DebuggerTuning = llvm::DebuggerKind::SCE; break; + case BBLLVMDebuggerKind::dbx: target_options.DebuggerTuning = llvm::DebuggerKind::DBX; break; } auto exception_handling = (BBLLVMExceptionHandling) create.target_options.exception_handling; switch (exception_handling) { - case BBLLVMExceptionHandling::none: target_options.ExceptionModel = ExceptionHandling::None; break; - case BBLLVMExceptionHandling::dwarf_cfi: target_options.ExceptionModel = ExceptionHandling::DwarfCFI; break; - case BBLLVMExceptionHandling::setjmp_longjmp: target_options.ExceptionModel = ExceptionHandling::SjLj; break; - case BBLLVMExceptionHandling::arm: target_options.ExceptionModel = ExceptionHandling::ARM; break; - case BBLLVMExceptionHandling::win_eh: target_options.ExceptionModel = ExceptionHandling::WinEH; break; - case BBLLVMExceptionHandling::wasm: target_options.ExceptionModel = ExceptionHandling::Wasm; break; - case BBLLVMExceptionHandling::aix: target_options.ExceptionModel = ExceptionHandling::AIX; break; - case BBLLVMExceptionHandling::zos: target_options.ExceptionModel = ExceptionHandling::ZOS; break; + case BBLLVMExceptionHandling::none: target_options.ExceptionModel = llvm::ExceptionHandling::None; break; + case BBLLVMExceptionHandling::dwarf_cfi: target_options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI; break; + case BBLLVMExceptionHandling::setjmp_longjmp: target_options.ExceptionModel = llvm::ExceptionHandling::SjLj; break; + case BBLLVMExceptionHandling::arm: target_options.ExceptionModel = llvm::ExceptionHandling::ARM; break; + case BBLLVMExceptionHandling::win_eh: target_options.ExceptionModel = llvm::ExceptionHandling::WinEH; break; + case BBLLVMExceptionHandling::wasm: target_options.ExceptionModel = llvm::ExceptionHandling::Wasm; break; + case BBLLVMExceptionHandling::aix: target_options.ExceptionModel = llvm::ExceptionHandling::AIX; break; + case BBLLVMExceptionHandling::zos: target_options.ExceptionModel = llvm::ExceptionHandling::ZOS; break; } target_options.LoopAlignment = create.target_options.loop_alignment; @@ -1520,26 +1407,26 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate auto emit_dwarf_unwind = (BBLLVMEmitDwarfUnwindType) create.target_options.mc.emit_dwarf_unwind; switch (emit_dwarf_unwind) { - case BBLLVMEmitDwarfUnwindType::always: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always; break; - case BBLLVMEmitDwarfUnwindType::no_compact_unwind: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::NoCompactUnwind; break; - case BBLLVMEmitDwarfUnwindType::normal: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Default; break; + case BBLLVMEmitDwarfUnwindType::always: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::Always; break; + case BBLLVMEmitDwarfUnwindType::no_compact_unwind: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::NoCompactUnwind; break; + case BBLLVMEmitDwarfUnwindType::normal: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::Default; break; } auto use_dwarf_directory = (BBLLVMDwarfDirectory) create.target_options.mc.use_dwarf_directory; switch (use_dwarf_directory) { - case BBLLVMDwarfDirectory::disable: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::DisableDwarfDirectory; break; - case BBLLVMDwarfDirectory::enable: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::EnableDwarfDirectory; break; - case BBLLVMDwarfDirectory::normal: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::DefaultDwarfDirectory; break; + case BBLLVMDwarfDirectory::disable: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::DisableDwarfDirectory; break; + case BBLLVMDwarfDirectory::enable: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::EnableDwarfDirectory; break; + case BBLLVMDwarfDirectory::normal: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::DefaultDwarfDirectory; break; } #if LLVM_VERSION_MAJOR >= 19 auto debug_compression_type = (BBLLVMDebugCompressionType) create.target_options.mc.debug_compression_type; switch (debug_compression_type) { - case BBLLVMDebugCompressionType::none: target_options.MCOptions.CompressDebugSections = DebugCompressionType::None; break; - case BBLLVMDebugCompressionType::zlib: target_options.MCOptions.CompressDebugSections = DebugCompressionType::Zlib; break; - case BBLLVMDebugCompressionType::zstd: target_options.MCOptions.CompressDebugSections = DebugCompressionType::Zstd; break; + case BBLLVMDebugCompressionType::none: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::None; break; + case BBLLVMDebugCompressionType::zlib: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::Zlib; break; + case BBLLVMDebugCompressionType::zstd: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::Zstd; break; } #endif @@ -1562,11 +1449,11 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate return target_machine; } -EXPORT void llvm_module_set_target(Module& module, TargetMachine& target_machine) +EXPORT void llvm_module_set_target(llvm::Module& module, llvm::TargetMachine& target_machine) { module.setDataLayout(target_machine.createDataLayout()); auto& triple_string = target_machine.getTargetTriple().getTriple(); - module.setTargetTriple(StringRef(triple_string)); + module.setTargetTriple(llvm::StringRef(triple_string)); } enum class BBLLVMOptimizationLevel : u8 @@ -1599,12 +1486,12 @@ struct BBLLVMOptimizationPipelineOptions static_assert(sizeof(BBLLVMOptimizationPipelineOptions) == sizeof(u64)); static_assert(BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT == 51); -EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine& target_machine, BBLLVMOptimizationPipelineOptions options) +EXPORT void llvm_module_run_optimization_pipeline(llvm::Module& module, llvm::TargetMachine& target_machine, BBLLVMOptimizationPipelineOptions options) { // TODO: PGO // TODO: CS profile - PipelineTuningOptions pipeline_tuning_options; + llvm::PipelineTuningOptions pipeline_tuning_options; pipeline_tuning_options.LoopUnrolling = options.loop_unrolling; pipeline_tuning_options.LoopInterleaving = options.loop_interleaving; pipeline_tuning_options.LoopVectorization = options.loop_vectorization; @@ -1615,24 +1502,24 @@ EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine& // TODO: instrumentation - LoopAnalysisManager loop_analysis_manager; - FunctionAnalysisManager function_analysis_manager; - CGSCCAnalysisManager cgscc_analysis_manager; - ModuleAnalysisManager module_analysis_manager; + llvm::LoopAnalysisManager loop_analysis_manager; + llvm::FunctionAnalysisManager function_analysis_manager; + llvm::CGSCCAnalysisManager cgscc_analysis_manager; + llvm::ModuleAnalysisManager module_analysis_manager; - PassBuilder pass_builder(&target_machine, pipeline_tuning_options); + llvm::PassBuilder pass_builder(&target_machine, pipeline_tuning_options); if (options.assignment_tracking && options.debug_info != 0) { - pass_builder.registerPipelineStartEPCallback([&](ModulePassManager& MPM, OptimizationLevel Level) { - MPM.addPass(AssignmentTrackingPass()); + pass_builder.registerPipelineStartEPCallback([&](llvm::ModulePassManager& MPM, llvm::OptimizationLevel Level) { + MPM.addPass(llvm::AssignmentTrackingPass()); }); } - Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718 + llvm::Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718 // TODO: add library (?) - std::unique_ptr TLII(llvm::driver::createTLII(target_triple, driver::VectorLibrary::NoLibrary)); - function_analysis_manager.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + std::unique_ptr TLII(llvm::driver::createTLII(target_triple, llvm::driver::VectorLibrary::NoLibrary)); + function_analysis_manager.registerPass([&] { return llvm::TargetLibraryAnalysis(*TLII); }); pass_builder.registerModuleAnalyses(module_analysis_manager); pass_builder.registerCGSCCAnalyses(cgscc_analysis_manager); @@ -1640,25 +1527,25 @@ EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine& pass_builder.registerLoopAnalyses(loop_analysis_manager); pass_builder.crossRegisterProxies(loop_analysis_manager, function_analysis_manager, cgscc_analysis_manager, module_analysis_manager); - ModulePassManager module_pass_manager; + llvm::ModulePassManager module_pass_manager; if (options.verify_module) { - module_pass_manager.addPass(VerifierPass()); + module_pass_manager.addPass(llvm::VerifierPass()); } bool thin_lto = false; bool lto = false; - OptimizationLevel optimization_level; + llvm::OptimizationLevel optimization_level; switch ((BBLLVMOptimizationLevel)options.optimization_level) { - case BBLLVMOptimizationLevel::O0: optimization_level = OptimizationLevel::O0; break; - case BBLLVMOptimizationLevel::O1: optimization_level = OptimizationLevel::O1; break; - case BBLLVMOptimizationLevel::O2: optimization_level = OptimizationLevel::O2; break; - case BBLLVMOptimizationLevel::O3: optimization_level = OptimizationLevel::O3; break; - case BBLLVMOptimizationLevel::Os: optimization_level = OptimizationLevel::Os; break; - case BBLLVMOptimizationLevel::Oz: optimization_level = OptimizationLevel::Oz; break; + case BBLLVMOptimizationLevel::O0: optimization_level = llvm::OptimizationLevel::O0; break; + case BBLLVMOptimizationLevel::O1: optimization_level = llvm::OptimizationLevel::O1; break; + case BBLLVMOptimizationLevel::O2: optimization_level = llvm::OptimizationLevel::O2; break; + case BBLLVMOptimizationLevel::O3: optimization_level = llvm::OptimizationLevel::O3; break; + case BBLLVMOptimizationLevel::Os: optimization_level = llvm::OptimizationLevel::Os; break; + case BBLLVMOptimizationLevel::Oz: optimization_level = llvm::OptimizationLevel::Oz; break; } // TODO: thin lto post-link @@ -1707,12 +1594,12 @@ enum class BBLLVMCodeGenerationPipelineResult : u8 failed_to_add_emit_passes = 2, }; -EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(Module& module, TargetMachine& target_machine, BBLLVMCodeGenerationPipelineOptions options) +EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(llvm::Module& module, llvm::TargetMachine& target_machine, BBLLVMCodeGenerationPipelineOptions options) { // We still use the legacy PM to run the codegen pipeline since the new PM // does not work with the codegen pipeline. // FIXME: make the new PM work with the codegen pipeline. - legacy::PassManager CodeGenPasses; + llvm::legacy::PassManager CodeGenPasses; #if LLVM_VERSION_MAJOR >= 19 if (options.optimize_when_possible) { @@ -1720,7 +1607,7 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli } #endif - raw_pwrite_stream* dwarf_object_file = 0; + llvm::raw_pwrite_stream* dwarf_object_file = 0; if (options.output_dwarf_file_path.length) { __builtin_trap(); @@ -1728,19 +1615,19 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli if (options.optimize_when_possible) { - Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718 + llvm::Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718 // TODO: add library (?) - std::unique_ptr TLII(llvm::driver::createTLII(target_triple, driver::VectorLibrary::NoLibrary)); - CodeGenPasses.add(new TargetLibraryInfoWrapperPass(*TLII)); + std::unique_ptr TLII(llvm::driver::createTLII(target_triple, llvm::driver::VectorLibrary::NoLibrary)); + CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII)); } - std::unique_ptr stream; + std::unique_ptr stream; if (options.output_file_path.length) { std::error_code error_code; - stream = std::make_unique(string_ref(options.output_file_path), error_code, sys::fs::OF_None); + stream = std::make_unique(string_ref(options.output_file_path), error_code, llvm::sys::fs::OF_None); if (error_code) { @@ -1752,12 +1639,12 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli stream = std::make_unique(); } - CodeGenFileType file_type; + llvm::CodeGenFileType file_type; switch ((BBLLVMCodeGenerationFileType)options.code_generation_file_type) { - case BBLLVMCodeGenerationFileType::assembly_file: file_type = CodeGenFileType::AssemblyFile; break; - case BBLLVMCodeGenerationFileType::object_file: file_type = CodeGenFileType::ObjectFile; break; - case BBLLVMCodeGenerationFileType::null: file_type = CodeGenFileType::Null; break; + case BBLLVMCodeGenerationFileType::assembly_file: file_type = llvm::CodeGenFileType::AssemblyFile; break; + case BBLLVMCodeGenerationFileType::object_file: file_type = llvm::CodeGenFileType::ObjectFile; break; + case BBLLVMCodeGenerationFileType::null: file_type = llvm::CodeGenFileType::Null; break; } auto disable_verify = !options.verify_module; diff --git a/src/llvm.h b/src/llvm.h index 8ab155a..6073542 100644 --- a/src/llvm.h +++ b/src/llvm.h @@ -1,24 +1,401 @@ -#include +#pragma once -namespace llvm +#include +#include +#include +#include +#include +#include + + +enum class BBLLVMUWTableKind : u64 { - class Type; - class Value; -} + None = 0, ///< No unwind table requested + Sync = 1, ///< "Synchronous" unwind tables + Async = 2, ///< "Asynchronous" unwind tables (instr precise) + Default = 2, +}; + +enum class BBLLVMFramePointerKind : u64 +{ + none = 0, + reserved = 1, + non_leaf = 2, + all = 3, +}; + +enum class ZeroCallUsedRegsKind : u64 +{ + all = 0, + skip = 1 << 0, + only_used = 1 << 1, + only_gpr = 1 << 2, + only_arg = 1 << 3, + used_gpr_arg = only_used | only_gpr | only_arg, + used_gpr = only_used | only_gpr, + used_arg = only_used | only_arg, + used = only_used, + all_gpr_arg = only_gpr | only_arg, + all_gpr = only_gpr, + all_arg = only_arg, +}; + +struct BBLLVMFunctionAttributesFlags0 +{ + u64 noreturn:1; + u64 cmse_ns_call:1; + u64 nounwind:1; + u64 returns_twice:1; + u64 cold:1; + u64 hot:1; + u64 no_duplicate:1; + u64 convergent:1; + u64 no_merge:1; + u64 will_return:1; + u64 no_caller_saved_registers:1; + u64 no_cf_check:1; + u64 no_callback:1; + u64 alloc_size:1; + u64 uniform_work_group_size:1; + u64 aarch64_pstate_sm_body:1; + u64 aarch64_pstate_sm_enabled:1; + u64 aarch64_pstate_sm_compatible:1; + u64 aarch64_preserves_za:1; + u64 aarch64_in_za:1; + u64 aarch64_out_za:1; + u64 aarch64_inout_za:1; + u64 aarch64_preserves_zt0:1; + u64 aarch64_in_zt0:1; + u64 aarch64_out_zt0:1; + u64 aarch64_inout_zt0:1; + u64 optimize_for_size:1; + u64 min_size:1; + u64 no_red_zone:1; + u64 indirect_tls_seg_refs:1; + u64 no_implicit_floats:1; + u64 sample_profile_suffix_elision_policy:1; + u64 memory_none:1; + u64 memory_readonly:1; + u64 memory_inaccessible_or_arg_memory_only:1; + u64 memory_arg_memory_only:1; + u64 strict_fp:1; + u64 no_inline:1; + u64 always_inline:1; + u64 guard_no_cf:1; + + // TODO: branch protection function attributes + // TODO: cpu features + + // Call-site begin + u64 call_no_builtins:1; + + BBLLVMFramePointerKind definition_frame_pointer_kind:2; + u64 definition_less_precise_fpmad:1; + u64 definition_null_pointer_is_valid:1; + u64 definition_no_trapping_fp_math:1; + u64 definition_no_infs_fp_math:1; + u64 definition_no_nans_fp_math:1; + u64 definition_approx_func_fp_math:1; + u64 definition_unsafe_fp_math:1; + u64 definition_use_soft_float:1; + u64 definition_no_signed_zeroes_fp_math:1; + u64 definition_stack_realignment:1; + u64 definition_backchain:1; + u64 definition_split_stack:1; + u64 definition_speculative_load_hardening:1; + ZeroCallUsedRegsKind definition_zero_call_used_registers:4; + // TODO: denormal builtins + u64 definition_non_lazy_bind:1; + u64 definition_cmse_nonsecure_entry:1; + BBLLVMUWTableKind definition_unwind_table_kind:2; +}; + +static_assert(sizeof(BBLLVMFunctionAttributesFlags0) == sizeof(u64)); + +struct BBLLVMFunctionAttributesFlags1 +{ + u64 definition_disable_tail_calls:1; + u64 definition_stack_protect_strong:1; + u64 definition_stack_protect:1; + u64 definition_stack_protect_req:1; + u64 definition_aarch64_new_za:1; + u64 definition_aarch64_new_zt0:1; + u64 definition_optimize_none:1; + u64 definition_naked:1; + u64 definition_inline_hint:1; + u64 _:55; +}; + +static_assert(sizeof(BBLLVMFunctionAttributesFlags1) == sizeof(u64)); + +struct BBLLVMFunctionAttributes +{ + String prefer_vector_width; + String stack_protector_buffer_size; + String definition_probe_stack; + String definition_stack_probe_size; + + BBLLVMFunctionAttributesFlags0 flags0; + BBLLVMFunctionAttributesFlags1 flags1; +}; + +static_assert(sizeof(BBLLVMFunctionAttributes) == 10 * sizeof(u64)); + +struct BBLLVMArgumentAttributes +{ + LLVMTypeRef semantic_type; + LLVMTypeRef abi_type; + u64 dereferenceable_bytes; + u32 alignment; + u32 no_alias:1; + u32 non_null:1; + u32 no_undef:1; + u32 sign_extend:1; + u32 zero_extend:1; + u32 in_reg:1; + u32 no_fp_class:10; + u32 struct_return:1; + u32 writable:1; + u32 dead_on_unwind:1; + u32 in_alloca:1; + u32 dereferenceable:1; + u32 dereferenceable_or_null:1; + u32 nest:1; + u32 by_value:1; + u32 by_reference:1; + u32 no_capture:1; + u32 _:6; +}; + +static_assert(sizeof(BBLLVMArgumentAttributes) == 2 * sizeof(Type*) + 2 * sizeof(u64)); + +struct BBLLVMAttributeListOptions +{ + BBLLVMFunctionAttributes function; + BBLLVMArgumentAttributes return_; + BBLLVMArgumentAttributes* argument_pointer; + u64 argument_count; +}; + +static_assert(sizeof(BBLLVMAttributeListOptions) == sizeof(BBLLVMFunctionAttributes) + sizeof(BBLLVMArgumentAttributes) + sizeof(void*) + sizeof(u64)); + +typedef void* BBLLVMAttributeList; + +enum class DwarfEmissionKind +{ + none, + full, + line_tables_only, +}; + +enum class DwarfType +{ + void_type = 0x0, + address = 0x1, + boolean = 0x2, + complex_float = 0x3, + float_type = 0x4, + signed_type = 0x5, + signed_char = 0x6, + unsigned_type = 0x7, + unsigned_char = 0x8, + + // DWARF 3. + imaginary_float = 0x9, + packed_decimal = 0xa, + numeric_string = 0xb, + edited = 0xc, + signed_fixed = 0xd, + unsigned_fixed = 0xe, + decimal_float = 0xf, + + // DWARF 4. + UTF = 0x10, + + // DWARF 5. + UCS = 0x11, + ASCII = 0x12, + + // HP extensions. + HP_float80 = 0x80, // Floating-point (80 bit). + HP_complex_float80 = 0x81, // Complex floating-point (80 bit). + HP_float128 = 0x82, // Floating-point (128 bit). + HP_complex_float128 = 0x83, // Complex fp (128 bit). + HP_floathpintel = 0x84, // Floating-point (82 bit IA64). + HP_imaginary_float80 = 0x85, + HP_imaginary_float128 = 0x86, + HP_VAX_float = 0x88, // F or G floating. + HP_VAX_float_d = 0x89, // D floating. + HP_packed_decimal = 0x8a, // Cobol. + HP_zoned_decimal = 0x8b, // Cobol. + HP_edited = 0x8c, // Cobol. + HP_signed_fixed = 0x8d, // Cobol. + HP_unsigned_fixed = 0x8e, // Cobol. + HP_VAX_complex_float = 0x8f, // F or G floating complex. + HP_VAX_complex_float_d = 0x90, // D floating complex. +}; + +enum class DIFlagsVisibility : u32 +{ + none = 0, + private_ = 1, + protected_ = 2, + public_ = 3, +}; + +enum class DIFlagsInheritance : u32 +{ + none = 0, + single_ = 1, + multiple_ = 2, + virtual_ = 3, +}; + +struct DIFlags +{ + DIFlagsVisibility visibility:2; + u32 forward_declaration:1; + u32 apple_block:1; + u32 block_by_ref_struct:1; + u32 virtual_:1; + u32 artificial:1; + u32 explicit_:1; + u32 prototyped:1; + u32 objective_c_class_complete:1; + u32 object_pointer:1; + u32 vector:1; + u32 static_member:1; + u32 lvalue_reference:1; + u32 rvalue_reference:1; + u32 reserved:1; + DIFlagsInheritance inheritance:2; + u32 introduced_virtual:1; + u32 bit_field:1; + u32 no_return:1; + u32 type_pass_by_value:1; + u32 type_pass_by_reference:1; + u32 enum_class:1; + u32 thunk:1; + u32 non_trivial:1; + u32 big_endian:1; + u32 little_endian:1; + u32 all_calls_described:1; + u32 _:3; +}; + +static_assert(sizeof(DIFlags) == sizeof(u32)); + +enum class LinkageType : u32 +{ + external, + available_externally, + link_once_any, + link_once_odr, + weak_any, + weak_odr, + appending, + internal, + private_, + external_weak, + common, +}; + +enum class LLVMCallingConvention : u32 +{ + c = 0, + fast = 8, + cold = 9, + ghc = 10, + hipe = 11, + anyreg = 13, + preserve_most = 14, + preserve_all = 15, + swift = 16, + cxx_fast_tls = 17, + x86_stdcall = 64, + x86_fastcall = 65, + arm_apcs = 66, + arm_aapcs = 67, + arm_aapcsvfp = 68, + msp430_interrupt = 69, + x86_thiscall = 70, + ptx_kernel = 71, + ptx_device = 72, + spir_func = 75, + spir_kernel = 76, + intel_oclbi = 77, + x86_64_system_v = 78, + win64 = 79, + x86_vector = 80, + hhvm = 81, + hhvmc = 82, + x86_interrupt = 83, + avr_interrupt = 84, + avr_signal = 85, + avr_builtin = 86, + amdgpu_vs = 87, + amdgpu_gs = 88, + amdgpu_ps = 89, + amdgpu_cs = 90, + amdgpu_kernel = 91, + x86_regcall = 92, + amdgpu_hs = 93, + msp430_builtin = 94, + amgpu_ls = 95, + amdgpu_es = 96, +}; fn bool llvm_initialized = false; -extern "C" void LLVMInitializeX86TargetInfo(); -extern "C" void LLVMInitializeX86Target(); -extern "C" void LLVMInitializeX86TargetMC(); -extern "C" void LLVMInitializeX86AsmPrinter(); -extern "C" void LLVMInitializeX86AsmParser(); -extern "C" void LLVMInitializeX86Disassembler(); +// extern "C" void LLVMInitializeX86TargetInfo(); +// extern "C" void LLVMInitializeX86Target(); +// extern "C" void LLVMInitializeX86TargetMC(); +// extern "C" void LLVMInitializeX86AsmPrinter(); +// extern "C" void LLVMInitializeX86AsmParser(); +// extern "C" void LLVMInitializeX86Disassembler(); extern "C" String llvm_default_target_triple(); extern "C" String llvm_host_cpu_name(); extern "C" String llvm_host_cpu_features(); +// extern "C" llvm::LLVMContext* LLVMContextCreate(); +extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name); +// extern "C" LLVMB LLVMCreateBuilderInContext(llvm::LLVMContext* context); +// extern "C" llvm::Type* LLVMVoidTypeInContext(llvm::LLVMContext* context); +// extern "C" llvm::Type* LLVMIntTypeInContext(llvm::LLVMContext* context, u32 bit_count); +// extern "C" llvm::Type* LLVMPointerTypeInContext(llvm::LLVMContext* context); +// extern "C" llvm::FunctionType* LLVMFunctionType(llvm::Type* return_type, llvm::Type** parameter_type_pointer, u32 parameter_type_count, int is_var_args); +// extern "C" LLVMIntrinsicId LLVMLookupIntrinsicID(const u8* name_pointer, u64 name_length); + +extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LinkageType linkage_type, unsigned address_space, String name); +// extern "C" void LLVMSetFunctionCallConv(llvm::Function* function, LLVMCallingConvention calling_convention); +extern "C" void llvm_function_set_attributes(LLVMValueRef function, BBLLVMAttributeList attribute_list); + +extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function); +// extern "C" void LLVMPositionBuilderAtEnd(llvm::Builder* builder, llvm::BasicBlock* basic_block); +// extern "C" llvm::DILocation* LLVMGetCurrentDebugLocation2(llvm::Builder* builder); +// extern "C" void LLVMSetCurrentDebugLocation2(llvm::Builder* builder, llvm::DILocation* location); + +extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name); +extern "C" bool llvm_value_has_one_use(LLVMValueRef value); +extern "C" LLVMValueRef llvm_basic_block_user_begin(LLVMBasicBlockRef basic_block); +extern "C" void llvm_basic_block_delete(LLVMBasicBlockRef basic_block); + +extern "C" BBLLVMAttributeList llvm_attribute_list_build(LLVMContextRef context, BBLLVMAttributeListOptions* attributes, bool call_site); +extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et); +extern "C" bool llvm_value_use_empty(LLVMValueRef value); +extern "C" bool llvm_function_verify(LLVMValueRef function_value, String* error_message); +extern "C" bool llvm_module_verify(LLVMModuleRef m, String* error_message); + +extern "C" String llvm_module_to_string(LLVMModuleRef module); + +// extern "C" llvm::DIBuilder* LLVMCreateDIBuilder(llvm::Module* module); +// extern "C" llvm::DIFile* LLVMDIBuilderCreateFile(llvm::DIBuilder* builder, const u8* file_name_pointer, u64 file_name_length, const u8* directory_name_pointer, u64 directory_name_length); +// extern "C" llvm::DICompileUnit* LLVMDIBuilderCreateCompileUnit(llvm::DIBuilder* builder, DwarfSourceLanguage dwarf_source_language, llvm::DIFile* file, const u8* producer_name_pointer, u64 producer_name_length, int is_optimized, const u8* flag_pointer, u64 flag_length, unsigned runtime_version, const u8* split_name_pointer, u64 split_name_length, DwarfEmissionKind emission_kind, unsigned debug_with_offset_id, int split_debug_inlining, int debug_info_for_profiling, const u8* sysroot_name_pointer, u64 sysroot_name_length, const u8* sdk_name_pointer, u64 sdk_name_length); +// extern "C" llvm::DIType* LLVMDIBuilderCreateBasicType(llvm::DIBuilder* builder, const u8* name_pointer, u64 name_length, u64 bit_count, DwarfType dwarf_type, DIFlags flags); +// extern "C" llvm::DISubroutineType* LLVMDIBuilderCreateSubroutineType(llvm::DIBuilder* builder, llvm::DIFile* file, llvm::DIType** parameter_type_pointer, u32 parameter_type_count, DIFlags flags); +// extern "C" llvm::DISubprogram* LLVMDIBuilderCreateFunction(llvm::DIBuilder* builder, llvm::DIScope* scope, const u8* name_pointer, u64 name_length, const u8* linkage_name_pointer, u64 linkage_name_length, llvm::DIFile* File, unsigned line_number, llvm::DISubroutineType* subroutine_type, int is_local_to_unit, int is_definition, unsigned scope_line, DIFlags flags, int is_optimized); + struct LLVMGlobal { String host_triple; @@ -28,9 +405,10 @@ struct LLVMGlobal global_variable LLVMGlobal llvm_global; -fn void initialize_all() +fn void llvm_initialize_all_raw() { assert(!llvm_initialized); + LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); @@ -44,3 +422,11 @@ fn void initialize_all() .host_cpu_features = llvm_host_cpu_features(), }; } + +fn void llvm_initialize_all() +{ + if (!llvm_initialized) + { + llvm_initialize_all_raw(); + } +} diff --git a/src/parser.cpp b/src/parser.cpp index e10167b..982fec5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2804,6 +2804,10 @@ fn Block* parse_block(Module* module, Scope* parent_scope) } auto* statement = parse_statement(module, scope); + if (!block->first_statement) + { + block->first_statement = statement; + } if (current_statement) {