diff --git a/src/compiler.bbb b/src/compiler.bbb index cf68319..97c841d 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -531,6 +531,32 @@ fail = fn () noreturn exit(1); } +LLVMContext = opaque; +LLVMModule = opaque; + +LLVMBuilder = opaque; + +LLVMValue = opaque; +LLVMType = opaque; +LLVMBasicBlock = opaque; +LLVMIntrinsicId = typealias u32; + +LLVMMetadata = opaque; +LLVMDIBuilder = opaque; + +LLVMTarget = opaque; +LLVMTargetDataLayout = opaque; +LLVMTargetMachine = opaque; +LLVMTargetMachineOptions = opaque; + +LLVMIntrinsicIndex = enum u32 +{ + trap, + va_start, + va_end, + va_copy, +} + CompilerCommand = enum { compile, @@ -548,6 +574,15 @@ BuildMode = enum aggressively_optimize_for_size, } +build_mode_is_optimized = fn (build_mode: BuildMode) u1 +{ + switch (build_mode) + { + .debug_none, .debug => { return 0; }, + else => { return 1; }, + } +} + CompileFile = struct { relative_file_path: []u8, @@ -644,6 +679,7 @@ Scope = struct { types: TypeList, parent: &Scope, + llvm: &LLVMMetadata, line: u32, column: u32, kind: ScopeKind, @@ -821,31 +857,6 @@ MacroInstantiation = struct foo: u32, } -LLVMContext = opaque; -LLVMModule = opaque; - -LLVMBuilder = opaque; - -LLVMValue = opaque; -LLVMType = opaque; -LLVMBasicBlock = opaque; -LLVMIntrinsicId = typealias u32; - -LLVMMetadata = opaque; -LLVMDIBuilder = opaque; - -LLVMTarget = opaque; -LLVMTargetMachine = opaque; -LLVMTargetMachineOptions = opaque; - -LLVMIntrinsicIndex = enum -{ - trap, - va_start, - va_end, - va_copy, -} - [extern] LLVMInitializeX86TargetInfo = fn [cc(c)] () void; [extern] LLVMInitializeX86Target = fn [cc(c)] () void; [extern] LLVMInitializeX86TargetMC = fn [cc(c)] () void; @@ -882,7 +893,7 @@ llvm_initialize_targets = fn () void } } -LLVMCodeGenerationOptimizationLevel = enum +LLVMCodeGenerationOptimizationLevel = enum u32 { none = 0, less = 1, @@ -890,16 +901,109 @@ LLVMCodeGenerationOptimizationLevel = enum aggressive = 3, } +LLVMDwarfSourceLanguage = enum u32 +{ + C89, + C, + Ada83, + C_plus_plus, + Cobol74, + Cobol85, + Fortran77, + Fortran90, + Pascal83, + Modula2, + // New in DWARF v3: + Java, + C99, + Ada95, + Fortran95, + PLI, + ObjC, + ObjC_plus_plus, + UPC, + D, + // New in DWARF v4: + Python, + // New in DWARF v5: + OpenCL, + Go, + Modula3, + Haskell, + C_plus_plus_03, + C_plus_plus_11, + OCaml, + Rust, + C11, + Swift, + Julia, + Dylan, + C_plus_plus_14, + Fortran03, + Fortran08, + RenderScript, + BLISS, + Kotlin, + Zig, + Crystal, + C_plus_plus_17, + C_plus_plus_20, + C17, + Fortran18, + Ada2005, + Ada2012, + HIP, + Assembly, + C_sharp, + Mojo, + GLSL, + GLSL_ES, + HLSL, + OpenCL_CPP, + CPP_for_OpenCL, + SYCL, + Ruby, + Move, + Hylo, + Metal, + + // Vendor extensions: + Mips_Assembler, + GOOGLE_RenderScript, + BORLAND_Delphi +} + +LLVMDwarfEmissionKind = enum u32 +{ + none, + full, + line_tables_only, +} + [extern] LLVMContextCreate = fn [cc(c)] () &LLVMContext; [extern] llvm_context_create_module = fn (context: &LLVMContext, name: []u8) &LLVMModule; [extern] LLVMCreateBuilderInContext = fn (context: &LLVMContext) &LLVMBuilder; +[extern] LLVMVoidTypeInContext = fn [cc(c)] (context: &LLVMContext) &LLVMType; +[extern] LLVMPointerTypeInContext = fn [cc(c)] (context: &LLVMContext, address_space: u32) &LLVMType; + +[extern] LLVMCreateDIBuilder = fn (module: &LLVMModule) &LLVMDIBuilder; +[extern] LLVMDIBuilderCreateFile = fn (di_builder: &LLVMDIBuilder, file_pointer: &u8, file_length: u64, directory_pointer: &u8, directory_length: u64) &LLVMMetadata; +[extern] LLVMDIBuilderCreateCompileUnit = fn (di_builder: &LLVMDIBuilder, language: LLVMDwarfSourceLanguage, file: &LLVMMetadata, producer_name_pointer: &u8, producer_name_length: u64, is_optimized: s32, flags_pointer: &u8, flags_length: u64, runtime_version: u32, split_name_pointer: &u8, split_name_length: u64, emission_kind: LLVMDwarfEmissionKind, dwo_id: u32, split_debug_inlining: s32, debug_info_for_profiling: s32, sysroot_pointer: &u8, sysroot_length: u64, sdk_pointer: &u8, sdk_length: u64) &LLVMMetadata; + +[extern] LLVMLookupIntrinsicID = fn [cc(c)] (name_pointer: &u8, name_length: u64) LLVMIntrinsicId; + [extern] LLVMCreateTargetMachineOptions = fn () &LLVMTargetMachineOptions; [extern] LLVMTargetMachineOptionsSetCPU = fn (target_machine_options: &LLVMTargetMachineOptions, cpu: &u8) void; [extern] LLVMTargetMachineOptionsSetFeatures = fn (target_machine_options: &LLVMTargetMachineOptions, features: &u8) void; [extern] LLVMTargetMachineOptionsSetCodeGenOptLevel = fn (target_machine_options: &LLVMTargetMachineOptions, optimization_level: LLVMCodeGenerationOptimizationLevel) void; [extern] LLVMGetTargetFromTriple = fn (target_triple: &u8, target_pointer: &&LLVMTarget, error_message_pointer: &&u8) s32; [extern] LLVMCreateTargetMachineWithOptions = fn (target: &LLVMTarget, target_triple: &u8, target_machine_options: &LLVMTargetMachineOptions) &LLVMTargetMachine; +[extern] LLVMCreateTargetDataLayout = fn (target_machine: &LLVMTargetMachine) &LLVMTargetDataLayout; +[extern] LLVMSetModuleDataLayout = fn (module: &LLVMModule, target_data_layout: &LLVMTargetDataLayout) void; +[extern] LLVMSetTarget = fn (module: &LLVMModule, target_triple: &u8) void; + +default_address_space: u32 = 0; ModuleLLVM = struct { @@ -908,7 +1012,8 @@ ModuleLLVM = struct builder: &LLVMBuilder, di_builder: &LLVMDIBuilder, file: &LLVMMetadata, - compile_unit: &LLVMMetadata, + target_machine: &LLVMTargetMachine, + target_data_layout: &LLVMTargetDataLayout, pointer_type: &LLVMType, void_type: &LLVMType, intrinsic_table: enum_array[LLVMIntrinsicIndex](LLVMIntrinsicId), @@ -2689,6 +2794,36 @@ emit = fn (module: &Module) void >m = llvm_context_create_module(context, module.name); >builder = LLVMCreateBuilderInContext(context); + >di_builder: &LLVMDIBuilder = zero; + >di_file: &LLVMMetadata = zero; + + if (module.has_debug_info) + { + di_builder = LLVMCreateDIBuilder(m); + >last_slash = string_last_character(module.path, '/'); + if (last_slash == string_no_match) + { + report_error(); + } + + >directory = module.path[..last_slash]; + >file_name = module.path[last_slash + 1..]; + + >di_file = LLVMDIBuilderCreateFile(di_builder, file_name.pointer, file_name.length, directory.pointer, directory.length); + + >language: LLVMDwarfSourceLanguage = .C17; + >producer_name = "bloat buster"; + >is_optimized = build_mode_is_optimized(module.build_mode); + >flags = ""; + >emission_kind: LLVMDwarfEmissionKind = .full; + >runtime_version: u32 = 0; + >split_name = ""; + >sysroot = ""; + >sdk = ""; + + module.scope.llvm = LLVMDIBuilderCreateCompileUnit(di_builder, language, di_file, producer_name.pointer, producer_name.length, #extend(is_optimized), flags.pointer, flags.length, runtime_version, split_name.pointer, split_name.length, emission_kind, 0, 0, #extend(is_optimized), sysroot.pointer, sysroot.length, sdk.pointer, sdk.length); + } + >target_triple: []u8 = undefined; >cpu_model: []u8 = undefined; >cpu_features: []u8 = undefined; @@ -2729,7 +2864,31 @@ emit = fn (module: &Module) void assert(!error_message); - LLVMCreateTargetMachineWithOptions(target, target_triple.pointer, target_machine_options); + >target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple.pointer, target_machine_options); + + >target_data_layout = LLVMCreateTargetDataLayout(target_machine); + LLVMSetModuleDataLayout(m, target_data_layout); + LLVMSetTarget(m, target_triple.pointer); + + module.llvm = { + .context = context, + .module = m, + .builder = builder, + .di_builder = di_builder, + .file = di_file, + .target_machine = target_machine, + .target_data_layout = target_data_layout, + .pointer_type = LLVMPointerTypeInContext(context, default_address_space), + .void_type = LLVMVoidTypeInContext(context), + zero, + }; + + for (i: 0..module.llvm.intrinsic_table.length) + { + >e: LLVMIntrinsicIndex = #enum_from_int(i); + >name = #enum_name(e); + module.llvm.intrinsic_table[i] = LLVMLookupIntrinsicID(name.pointer, name.length); + } } compile = fn (arena: &Arena, options: CompileOptions) void diff --git a/src/compiler.hpp b/src/compiler.hpp index b85a8ab..ff9ae29 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -597,6 +597,7 @@ fn u32 get_byte_alignment(Type* type) return result; } break; case TypeId::pointer: + case TypeId::opaque: { return 8; } break; @@ -860,6 +861,7 @@ enum class UnaryId bitwise_not, dereference, pointer_from_int, + enum_from_int, }; struct ValueUnary diff --git a/src/emitter.cpp b/src/emitter.cpp index 656b7ef..464114c 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -176,6 +176,7 @@ fn bool is_promotable_integer_type_for_abi(Type* type) 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); case TypeId::enumerator: return is_promotable_integer_type_for_abi(type->enumerator.backing_type); + case TypeId::pointer: return false; default: unreachable(); } } @@ -927,6 +928,7 @@ fn void resolve_type_in_place_abi(Module* module, Type* type) result = LLVMIntTypeInContext(module->llvm.context, type->integer.bit_count); break; case TypeId::pointer: + case TypeId::opaque: result = module->llvm.pointer_type; break; case TypeId::array: @@ -1015,6 +1017,7 @@ fn void resolve_type_in_place_memory(Module* module, Type* type) case TypeId::void_type: case TypeId::noreturn: case TypeId::pointer: + case TypeId::opaque: case TypeId::array: case TypeId::structure: case TypeId::enum_array: @@ -2220,6 +2223,7 @@ fn bool unary_is_boolean(UnaryId id) case UnaryId::bitwise_not: case UnaryId::dereference: case UnaryId::pointer_from_int: + case UnaryId::enum_from_int: return false; } } @@ -2265,7 +2269,20 @@ fn bool binary_is_shortcircuiting(BinaryId id) } } -fn void analyze_type(Module* module, Value* value, Type* expected_type, bool must_be_constant); +enum class IndexType +{ + none, + array, + enum_array, +}; + +struct TypeAnalysis +{ + bool must_be_constant; + bool is_index; +}; + +fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis); fn void analyze_binary_type(Module* module, Value* left, Value* right, bool is_boolean, Type* expected_type, bool must_be_constant) { @@ -2296,19 +2313,19 @@ fn void analyze_binary_type(Module* module, Value* left, Value* right, bool is_b { if (left_constant) { - analyze_type(module, right, 0, must_be_constant); - analyze_type(module, left, right->type, must_be_constant); + analyze_type(module, right, 0, { .must_be_constant = must_be_constant }); + analyze_type(module, left, right->type, { .must_be_constant = must_be_constant }); } else { - analyze_type(module, left, 0, must_be_constant); - analyze_type(module, right, left->type, must_be_constant); + analyze_type(module, left, 0, { .must_be_constant = must_be_constant }); + analyze_type(module, right, left->type, { .must_be_constant = must_be_constant }); } } else if (!is_boolean && expected_type) { - analyze_type(module, left, expected_type, must_be_constant); - analyze_type(module, right, expected_type, must_be_constant); + analyze_type(module, left, expected_type, { .must_be_constant = must_be_constant }); + analyze_type(module, right, expected_type, { .must_be_constant = must_be_constant }); } else { @@ -2622,9 +2639,8 @@ fn void copy_block(Module* module, Scope* parent_scope, BlockCopy copy) } } -fn void analyze_type(Module* module, Value* value, Type* expected_type, bool must_be_constant) +fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis) { - unused(must_be_constant); assert(!value->type); assert(!value->llvm); @@ -2674,6 +2690,14 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { case ValueId::constant_integer: { + if (!expected_type) + { + if (analysis.is_index) + { + expected_type = uint64(module); + } + } + if (!expected_type) { report_error(); @@ -2726,7 +2750,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } auto extended_value = unary_value; - analyze_type(module, extended_value, 0, must_be_constant); + analyze_type(module, extended_value, 0, { .must_be_constant = analysis.must_be_constant }); auto source = extended_value->type; assert(source); @@ -2750,7 +2774,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus report_error(); } - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto expected_bit_size = get_bit_size(expected_type); auto source_bit_size = get_bit_size(unary_value->type); @@ -2763,7 +2787,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } break; case UnaryId::dereference: { - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); if (value->kind == ValueKind::left) { report_error(); @@ -2777,7 +2801,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } break; case UnaryId::int_from_enum: { - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto value_enum_type = unary_value->type; if (value_enum_type->id != TypeId::enumerator) @@ -2792,7 +2816,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } break; case UnaryId::int_from_pointer: { - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto value_enum_type = unary_value->type; if (value_enum_type->id != TypeId::pointer) @@ -2815,7 +2839,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus report_error(); } - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto value_pointer_type = unary_value->type; if (value_pointer_type == expected_type) { @@ -2833,7 +2857,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { auto string_type = get_slice_type(module, uint8(module)); typecheck(module, expected_type, string_type); - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto enum_type = unary_value->type; if (enum_type->id != TypeId::enumerator) { @@ -2948,7 +2972,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus report_error(); } - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); auto unary_value_type = unary_value->type; if (unary_value_type->id != TypeId::integer) { @@ -2961,6 +2985,32 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus report_error(); } + value_type = expected_type; + } break; + case UnaryId::enum_from_int: + { + if (!expected_type) + { + report_error(); + } + + if (expected_type->id != TypeId::enumerator) + { + report_error(); + } + + analyze_type(module, unary_value, expected_type->enumerator.backing_type, { .must_be_constant = analysis.must_be_constant }); + auto unary_value_type = unary_value->type; + if (unary_value_type->id != TypeId::integer) + { + report_error(); + } + + if (get_bit_size(unary_value_type) != get_bit_size(expected_type)) + { + report_error(); + } + value_type = expected_type; } break; default: @@ -2968,12 +3018,12 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto is_boolean = unary_is_boolean(unary_id); if (is_boolean) { - analyze_type(module, unary_value, 0, must_be_constant); + analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant }); value_type = uint1(module); } else { - analyze_type(module, unary_value, expected_type, must_be_constant); + analyze_type(module, unary_value, expected_type, { .must_be_constant = analysis.must_be_constant }); value_type = unary_value->type; } @@ -3031,7 +3081,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus case ValueId::binary: { auto is_boolean = binary_is_boolean(value->binary.id); - analyze_binary_type(module, value->binary.left, value->binary.right, is_boolean, expected_type, must_be_constant); + analyze_binary_type(module, value->binary.left, value->binary.right, is_boolean, expected_type, analysis.must_be_constant); check_types(module, value->binary.left->type, value->binary.right->type); value_type = is_boolean ? uint1(module) : value->binary.left->type; @@ -3050,7 +3100,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { auto call = &value->call; auto callable = call->callable; - analyze_type(module, callable, 0, must_be_constant); + analyze_type(module, callable, 0, { .must_be_constant = analysis.must_be_constant }); Type* function_type = 0; switch (callable->id) { @@ -3101,14 +3151,14 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { auto* argument_type = semantic_argument_types[i]; auto* call_argument = call_arguments[i]; - analyze_type(module, call_argument, argument_type, must_be_constant); + analyze_type(module, call_argument, argument_type, { .must_be_constant = analysis.must_be_constant }); check_types(module, argument_type, call_argument->type); } for (u64 i = semantic_argument_types.length; i < call_arguments.length; i += 1) { auto* call_argument = call_arguments[i]; - analyze_type(module, call_argument, 0, must_be_constant); + analyze_type(module, call_argument, 0, { .must_be_constant = analysis.must_be_constant }); } auto semantic_return_type = function_type->function.semantic_return_type; @@ -3144,7 +3194,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto* element_type = expected_type->array.element_type; for (auto value : values) { - analyze_type(module, value, element_type, must_be_constant); + analyze_type(module, value, element_type, { .must_be_constant = analysis.must_be_constant }); is_constant = is_constant && value->is_constant(); } @@ -3169,7 +3219,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus for (auto value : values) { - analyze_type(module, value, expected_type, must_be_constant); + analyze_type(module, value, expected_type, { .must_be_constant = analysis.must_be_constant }); is_constant = is_constant && value->is_constant(); @@ -3209,7 +3259,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { auto array_like = value->array_expression.array_like; array_like->kind = ValueKind::left; - analyze_type(module, array_like, 0, must_be_constant); + analyze_type(module, array_like, 0, { .must_be_constant = analysis.must_be_constant }); assert(array_like->kind == ValueKind::left); auto array_like_type = array_like->type; if (array_like_type->id != TypeId::pointer) @@ -3218,7 +3268,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } auto pointer_element_type = array_like_type->pointer.element_type; - analyze_type(module, value->array_expression.index, pointer_element_type->id == TypeId::enum_array ? pointer_element_type->enum_array.enum_type : uint64(module), must_be_constant); + analyze_type(module, value->array_expression.index, 0, { .must_be_constant = analysis.must_be_constant, .is_index = true }); Type* element_type = 0; switch (pointer_element_type->id) @@ -3281,7 +3331,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { auto aggregate = value->field_access.aggregate; auto field_name = value->field_access.field_name; - analyze_type(module, aggregate, 0, must_be_constant); + analyze_type(module, aggregate, 0, { .must_be_constant = analysis.must_be_constant }); if (aggregate->kind == ValueKind::right) { @@ -3373,6 +3423,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto field = fields[i]; value_type = field.type; } break; + case TypeId::enum_array: case TypeId::array: { if (!field_name.equal(string_literal("length"))) @@ -3391,7 +3442,16 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } else { - trap(); + if (resolved_aggregate_type->id == TypeId::enum_array) + { + auto enum_type = resolved_aggregate_type->enum_array.enum_type; + auto backing_type = enum_type->enumerator.backing_type; + value_type = backing_type; + } + else + { + report_error(); + } } } break; case TypeId::pointer: report_error(); // Double indirection is not allowed @@ -3413,7 +3473,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus report_error(); } - analyze_type(module, array_like, 0, must_be_constant); + analyze_type(module, array_like, 0, { .must_be_constant = analysis.must_be_constant }); auto pointer_type = array_like->type; if (pointer_type->id != TypeId::pointer) @@ -3462,7 +3522,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus { if (index) { - analyze_type(module, index, index_type, must_be_constant); + analyze_type(module, index, index_type, { .must_be_constant = analysis.must_be_constant }); if (index->type->id != TypeId::integer) { @@ -3487,7 +3547,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } break; case ValueId::va_arg: { - analyze_type(module, value->va_arg.va_list, get_pointer_type(module, get_va_list_type(module)), must_be_constant); + analyze_type(module, value->va_arg.va_list, get_pointer_type(module, get_va_list_type(module)), { .must_be_constant = analysis.must_be_constant }); value_type = value->va_arg.type; typecheck(module, expected_type, value_type); } break; @@ -3569,7 +3629,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto field = fields[declaration_index]; auto declaration_type = field.type; - analyze_type(module, value, declaration_type, must_be_constant); + analyze_type(module, value, declaration_type, { .must_be_constant = analysis.must_be_constant }); is_constant = is_constant && value->is_constant(); } @@ -3627,7 +3687,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto field = fields[declaration_index]; auto declaration_type = field.type; - analyze_type(module, value, declaration_type, must_be_constant); + analyze_type(module, value, declaration_type, { .must_be_constant = analysis.must_be_constant }); is_constant = is_constant && value->is_constant(); } @@ -3660,7 +3720,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus } auto field = &fields[i]; - analyze_type(module, initialization_value, field->type, must_be_constant); + analyze_type(module, initialization_value, field->type, { .must_be_constant = analysis.must_be_constant }); } break; case TypeId::enum_array: { @@ -3719,7 +3779,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus is_ordered = is_ordered && declaration_index == initialization_index; - analyze_type(module, value, element_type, must_be_constant); + analyze_type(module, value, element_type, { .must_be_constant = analysis.must_be_constant }); is_constant = is_constant && value->is_constant(); } @@ -3747,9 +3807,9 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto condition = value->select.condition; auto true_value = value->select.true_value; auto false_value = value->select.false_value; - analyze_type(module, condition, 0, must_be_constant); + analyze_type(module, condition, 0, { .must_be_constant = analysis.must_be_constant }); auto is_boolean = false; - analyze_binary_type(module, true_value, false_value, is_boolean, expected_type, must_be_constant); + analyze_binary_type(module, true_value, false_value, is_boolean, expected_type, analysis.must_be_constant); auto left_type = true_value->type; auto right_type = false_value->type; @@ -4081,7 +4141,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto string_type = get_slice_type(module, uint8(module)); - analyze_type(module, enum_string_value, string_type, must_be_constant); + analyze_type(module, enum_string_value, string_type, { .must_be_constant = analysis.must_be_constant }); value_type = struct_type; } break; case ValueId::undefined: @@ -4219,7 +4279,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto argument_type = declaration_argument.variable.type; assert(argument_type); - analyze_type(module, instantiation_argument, argument_type, must_be_constant); + analyze_type(module, instantiation_argument, argument_type, { .must_be_constant = analysis.must_be_constant }); } LLVMMetadataRef type_buffer[64]; @@ -4263,7 +4323,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus auto argument_type = declaration_argument.variable.type; assert(argument_type); - analyze_type(module, instantiation_argument, argument_type, must_be_constant); + analyze_type(module, instantiation_argument, argument_type, { .must_be_constant = analysis.must_be_constant }); } } @@ -4918,7 +4978,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm, { src->type = 0; src->kind = ValueKind::left; - analyze_type(module, src, 0, false); + analyze_type(module, src, 0, {}); } } @@ -5066,7 +5126,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm, assert(src->kind == ValueKind::right); src->type = 0; src->kind = ValueKind::left; - analyze_type(module, src, pointer_type, false); + analyze_type(module, src, pointer_type, {}); } } else @@ -5771,11 +5831,31 @@ fn LLVMValueRef emit_field_access(Module* module, Value* value, LLVMValueRef lef return trunc; } break; + case TypeId::enum_array: case TypeId::array: { assert(value->field_access.field_name.equal(string_literal("length"))); auto array_length_type = get_llvm_type(value->type, type_kind); - auto result = LLVMConstInt(array_length_type, resolved_aggregate_type->array.element_count, false); + u64 array_element_count = 0; + + switch (resolved_aggregate_type->id) + { + case TypeId::enum_array: + { + auto enum_type = resolved_aggregate_type->enum_array.enum_type; + assert(enum_type->id == TypeId::enumerator); + array_element_count = enum_type->enumerator.fields.length; + } break; + case TypeId::array: + { + array_element_count = resolved_aggregate_type->array.element_count; + } break; + default: unreachable(); + } + + assert(array_element_count); + + auto result = LLVMConstInt(array_length_type, array_element_count, false); return result; } break; default: unreachable(); @@ -6619,6 +6699,10 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect { llvm_value = LLVMBuildIntToPtr(module->llvm.builder, llvm_unary_value, resolved_value_type->llvm.abi, ""); } break; + case UnaryId::enum_from_int: + { + llvm_value = llvm_unary_value; + } break; } } break; case ValueId::unary_type: @@ -7375,7 +7459,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect fn void analyze_value(Module* module, Value* value, Type* expected_type, TypeKind type_kind, bool must_be_constant) { - analyze_type(module, value, expected_type, must_be_constant); + analyze_type(module, value, expected_type, { .must_be_constant = must_be_constant }); emit_value(module, value, type_kind, must_be_constant); } @@ -7453,7 +7537,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 report_error(); } - analyze_type(module, return_value, return_abi.semantic_type, false); + 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; @@ -7468,7 +7552,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 auto macro_instantiation = module->current_macro_instantiation; auto return_type = macro_instantiation->return_type; assert(return_type); - analyze_type(module, return_value, return_type, false); + analyze_type(module, return_value, return_type, {}); emit_assignment(module, macro_instantiation->return_alloca, get_pointer_type(module, return_type), return_value); LLVMBuildBr(module->llvm.builder, macro_instantiation->return_block); LLVMClearInsertionPosition(module->llvm.builder); @@ -7483,7 +7567,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 auto local = statement->local; auto expected_type = local->variable.type; assert(!local->variable.storage); - analyze_type(module, local->variable.initial_value, expected_type, false); + analyze_type(module, local->variable.initial_value, expected_type, {}); local->variable.type = expected_type ? expected_type : local->variable.initial_value->type; assert(local->variable.type); if (expected_type) @@ -7624,7 +7708,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 { case StatementAssignmentId::assign: { - analyze_type(module, right, element_type, false); + analyze_type(module, right, element_type, {}); emit_assignment(module, left_llvm, left_type, right); } break; case StatementAssignmentId::assign_add: @@ -7875,7 +7959,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 auto kind = left_values[i]; auto right = right_values[i]; - analyze_type(module, right, 0, false); + analyze_type(module, right, 0, {}); Type* aggregate_type = 0; @@ -8178,7 +8262,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 } break; default: { - analyze_type(module, end, 0, false); + analyze_type(module, end, 0, {}); auto end_type = end->type; assert(end_type); start->type = end_type; @@ -8195,7 +8279,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 { if (!right->type) { - analyze_type(module, right, local_type, false); + analyze_type(module, right, local_type, {}); } } diff --git a/src/parser.cpp b/src/parser.cpp index 577a28a..73606fb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4,6 +4,7 @@ enum class ValueIntrinsic { align_of, byte_size, + enum_from_int, enum_name, extend, integer_max, @@ -855,6 +856,7 @@ fn Token tokenize(Module* module) String value_intrinsics[] = { string_literal("align_of"), string_literal("byte_size"), + string_literal("enum_from_int"), string_literal("enum_name"), string_literal("extend"), string_literal("integer_max"), @@ -1363,6 +1365,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder) switch (intrinsic) { + case ValueIntrinsic::enum_from_int: case ValueIntrinsic::enum_name: case ValueIntrinsic::extend: case ValueIntrinsic::int_from_enum: @@ -1375,6 +1378,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder) UnaryId id; switch (intrinsic) { + case ValueIntrinsic::enum_from_int: id = UnaryId::enum_from_int; break; case ValueIntrinsic::enum_name: id = UnaryId::enum_name; break; case ValueIntrinsic::extend: id = UnaryId::extend; break; case ValueIntrinsic::int_from_enum: id = UnaryId::int_from_enum; break;