From 41a2576064cd557d3228541259e241661efd7d1d Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Sun, 8 Jun 2025 09:07:52 -0600 Subject: [PATCH] wip --- CMakeLists.txt | 2 +- src/compiler.bbb | 1354 +++++++++++++++++++++++++++++++++++++++++++--- src/emitter.cpp | 193 ++++--- src/llvm.cpp | 209 +------ src/llvm.hpp | 21 - src/parser.cpp | 12 +- 6 files changed, 1396 insertions(+), 395 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 708b224..ae44d6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,6 @@ target_link_libraries(llvm_bindings PUBLIC target_link_libraries(bb PUBLIC llvm_bindings) -add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -funsigned-char -fwrapv -fno-strict-aliasing) +add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -fno-signed-char -fwrapv -fno-strict-aliasing) add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}") add_compile_definitions(BB_CI=${BB_CI}) diff --git a/src/compiler.bbb b/src/compiler.bbb index b7e6b00..e052f54 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -502,6 +502,7 @@ arena_duplicate_string = fn (arena: &Arena, string: []u8) []u8 { >result = arena_allocate_bytes(arena, string.length + 1, 1); memcpy(result, string.pointer, string.length); + result[string.length] = 0; return result[..string.length]; } @@ -847,7 +848,8 @@ LLVMAttributeIndex = enum u32 LLVMLinkage = enum u32 { - external, // Externally visible function available_externally, + external, // Externally visible function + available_externally, link_once_any, // Keep one copy of function when linking (inline)*/ link_once_odr, // Same, but only replaced by something @@ -866,6 +868,15 @@ LLVMLinkage = enum u32 linker_private_weak // Like LinkerPrivate, but is weak. */ } +LLVMThreadLocalMode = enum u32 +{ + not_thread_local = 0, + general_dynamic = 1, + local_dynamic = 2, + initial_exec = 3, + local_exec = 4, +} + LLVMCallingConvention = enum { c = 0, @@ -911,6 +922,13 @@ LLVMCallingConvention = enum amdgpu_es = 96 } +LLVMVerifyFailureAction = enum u32 +{ + abort, + print, + return, +} + CompilerCommand = enum { compile, @@ -1315,11 +1333,19 @@ TypeFunction = struct next: &Type, } +TypeArray = struct +{ + element_type: &Type, + element_count: u64, + next: &Type, +} + TypeContent = union { integer: TypeInteger, function: TypeFunction, pointer: TypePointer, + array: TypeArray, } TypeLLVM = struct @@ -1417,6 +1443,10 @@ get_byte_size = fn (type: &Type) u64 assert(byte_count == 1 or byte_count == 2 or byte_count == 4 or byte_count == 8 or byte_count == 16); return byte_count; }, + .pointer => + { + return 8; + }, else => { #trap(); @@ -1432,6 +1462,10 @@ get_bit_size = fn (type: &Type) u64 { return type.content.integer.bit_count; }, + .array => + { + return get_bit_size(type.content.array.element_type); + }, else => { #trap(); @@ -1449,6 +1483,12 @@ get_byte_alignment = fn (type: &Type) u32 assert(aligned_byte_count == 1 or aligned_byte_count == 2 or aligned_byte_count == 4 or aligned_byte_count == 8 or aligned_byte_count == 16); return aligned_byte_count; }, + .pointer => { return 8; }, + .array => + { + >element_type = type.content.array.element_type; + return get_byte_alignment(element_type); + }, else => { #trap(); @@ -1514,6 +1554,11 @@ ValueId = enum variable, local, unary_type, + macro_reference, + call, + array_initialization, + array_expression, + slice_expression, } ValueConstantInteger = struct @@ -1673,6 +1718,32 @@ ValueBinary = struct id: BinaryId, } +ValueCall = struct +{ + callable: &Value, + arguments: []&Value, + function_type: &Type, +} + +ValueArrayInitialization = struct +{ + values: []&Value, + is_constant: u1, +} + +ValueArrayExpression = struct +{ + array_like: &Value, + index: &Value, +} + +ValueSliceExpression = struct +{ + array_like: &Value, + start: &Value, + end: &Value, +} + ValueContent = union { constant_integer: ValueConstantInteger, @@ -1681,6 +1752,10 @@ ValueContent = union binary: ValueBinary, variable: &Variable, unary_type: ValueUnaryType, + call: ValueCall, + array_initialization: ValueArrayInitialization, + array_expression: ValueArrayExpression, + slice_expression: ValueSliceExpression, } ValueKind = enum @@ -1742,13 +1817,13 @@ MacroInstantiation = struct [extern] LLVMInitializeX86AsmParser = fn [cc(c)] () void; [extern] LLVMInitializeX86Disassembler = fn [cc(c)] () void; -[extern] llvm_default_target_triple = fn [cc(c)] () []u8; -[extern] llvm_host_cpu_name = fn [cc(c)] () []u8; -[extern] llvm_host_cpu_features = fn [cc(c)] () []u8; +[extern] LLVMGetDefaultTargetTriple = fn [cc(c)] () &u8; +[extern] LLVMGetHostCPUName = fn [cc(c)] () &u8; +[extern] LLVMGetHostCPUFeatures = fn [cc(c)] () &u8; -host_target_triple: []u8 = zero; -host_cpu_model: []u8 = zero; -host_cpu_features: []u8 = zero; +host_target_triple: &u8 = zero; +host_cpu_model: &u8 = zero; +host_cpu_features: &u8 = zero; llvm_targets_initialized: u1 = 0; @@ -1763,9 +1838,9 @@ llvm_initialize_targets = fn () void LLVMInitializeX86AsmParser(); LLVMInitializeX86Disassembler(); - host_target_triple = llvm_default_target_triple(); - host_cpu_model = llvm_host_cpu_name(); - host_cpu_features = llvm_host_cpu_features(); + host_target_triple = LLVMGetDefaultTargetTriple(); + host_cpu_model = LLVMGetHostCPUName(); + host_cpu_features = LLVMGetHostCPUFeatures(); llvm_targets_initialized = 1; } @@ -2017,13 +2092,14 @@ LLVMICmpPredicate = enum u32 } [extern] LLVMContextCreate = fn [cc(c)] () &LLVMContext; -[extern] llvm_context_create_module = fn (context: &LLVMContext, name: []u8) &LLVMModule; +[extern] LLVMModuleCreateWithNameInContext = fn (name: &u8, context: &LLVMContext) &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] LLVMIntTypeInContext = fn [cc(c)] (context: &LLVMContext, bit_count: u32) &LLVMType; [extern] LLVMFunctionType = fn [cc(c)] (return_type: &LLVMType, argument_pointer: &&LLVMType, argument_count: u32, is_variable_argument: s32) &LLVMType; +[extern] LLVMArrayType2 = fn [cc(c)] (element_type: &LLVMType, element_count: u64) &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; @@ -2032,6 +2108,7 @@ LLVMICmpPredicate = enum u32 [extern] LLVMDIBuilderCreateBasicType = fn [cc(c)] (di_builder: &LLVMDIBuilder, name_pointer: &u8, name_length: u64, bit_size: u64, dwarf_encoding: LLVMDwarfTypeEncoding, flags: LLVMDIFlags) &LLVMMetadata; [extern] LLVMDIBuilderCreatePointerType = fn [cc(c)] (di_builder: &LLVMDIBuilder, element_type: &LLVMMetadata, bit_size: u64, bit_alignment: u32, address_space: u32, name_pointer: &u8, name_length: u64) &LLVMMetadata; [extern] LLVMDIBuilderCreateSubroutineType = fn [cc(c)] (di_builder: &LLVMDIBuilder, file: &LLVMMetadata, argument_type_pointer: &&LLVMMetadata, argument_type_count: u32, flags: LLVMDIFlags) &LLVMMetadata; +[extern] LLVMDIBuilderCreateArrayType = fn [cc(c)] (di_builder: &LLVMDIBuilder, bit_size: u64, bit_alignment: u32, element_type: &LLVMMetadata, subscript_pointer: &LLVMMetadata, subscript_count: u32) &LLVMMetadata; [extern] LLVMDIBuilderCreateFunction = fn [cc(c)] (di_builder: &LLVMDIBuilder, scope: &LLVMMetadata, name_pointer: &u8, name_length: u64, linkage_name_pointer: &u8, linkage_name_length: u64, file: &LLVMMetadata, line: u32, type: &LLVMMetadata, is_local_to_unit: s32, is_definition: s32, scope_line: u32, flags: LLVMDIFlags, is_optimized: s32) &LLVMMetadata; [extern] LLVMDIBuilderFinalizeSubprogram = fn [cc(c)] (di_builder: &LLVMDIBuilder, subprogram: &LLVMMetadata) void; @@ -2055,15 +2132,31 @@ LLVMICmpPredicate = enum u32 [extern] LLVMCreateTypeAttribute = fn [cc(c)] (context: &LLVMContext, attribute_id: LLVMAttributeId, type: &LLVMType) &LLVMAttribute; [extern] LLVMCreateStringAttribute = fn [cc(c)] (context: &LLVMContext, attribute_key_pointer: &u8, attribute_key_length: u64, attribute_value_pointer: &u8, attribute_value_length: u64) &LLVMAttribute; [extern] LLVMAddAttributeAtIndex = fn [cc(c)] (value: &LLVMValue, index: u32, attribute: &LLVMAttribute) void; +[extern] LLVMAddCallSiteAttribute = fn [cc(c)] (value: &LLVMValue, index: u32, attribute: &LLVMAttribute) void; [extern] LLVMGetParams = fn [cc(c)] (function: &LLVMValue, parameter_pointer: &&LLVMValue) void; -[extern] llvm_context_create_basic_block = fn [cc(c)] (context: &LLVMContext, name: []u8, parent_function: &LLVMValue) &LLVMBasicBlock; +[extern] LLVMAppendBasicBlockInContext = fn [cc(c)] (context: &LLVMContext, function: &LLVMValue, name: &u8) &LLVMBasicBlock; + [extern] LLVMPositionBuilderAtEnd = fn [cc(c)] (builder: &LLVMBuilder, basic_block: &LLVMBasicBlock) void; [extern] LLVMClearInsertionPosition = fn [cc(c)] (builder: &LLVMBuilder) void; [extern] LLVMSetCurrentDebugLocation2 = fn [cc(c)] (builder: &LLVMBuilder, debug_location: &LLVMMetadata) void; -[extern] llvm_builder_create_alloca = fn [cc(c)] (builder: &LLVMBuilder, type: &LLVMType, address_space: u32, alignment: u32, name: []u8) &LLVMValue; +[extern] LLVMSetAlignment = fn [cc(c)] (value: &LLVMValue, alignment: u32) void; +[extern] LLVMBuildAlloca = fn [cc(c)] (builder: &LLVMBuilder, type: &LLVMType, name: &u8) &LLVMValue; + +llvm_create_alloca = fn (builder: &LLVMBuilder, type: &LLVMType, alignment: u32, name: []u8) &LLVMValue +{ + assert(name.pointer[name.length] == 0); + >alloca = LLVMBuildAlloca(builder, type, name.pointer); + LLVMSetAlignment(alloca, alignment); + return alloca; +} + +llvm_create_global_variable = fn (module: &LLVMModule, type: &LLVMType, is_constant: u1, linkage: LLVMLinkage, initial_value: &LLVMValue, name: []u8, thread_local_mode: LLVMThreadLocalMode, externally_initialized: u1) &LLVMValue +{ +} + [extern] LLVMBuildStore = fn [cc(c)] (builder: &LLVMBuilder, source: &LLVMValue, destination: &LLVMValue) &LLVMValue; [extern] LLVMBuildLoad2 = fn [cc(c)] (builder: &LLVMBuilder, type: &LLVMType, pointer: &LLVMValue, name: &u8) &LLVMValue; @@ -2071,6 +2164,7 @@ LLVMICmpPredicate = enum u32 [extern] LLVMBuildRetVoid = fn [cc(c)] (builder: &LLVMBuilder) &LLVMValue; [extern] LLVMBuildBr = fn [cc(c)] (builder: &LLVMBuilder, target_block: &LLVMBasicBlock) &LLVMValue; +[extern] LLVMBuildCondBr = fn [cc(c)] (builder: &LLVMBuilder, condition: &LLVMValue, taken_block: &LLVMBasicBlock, not_taken_block: &LLVMBasicBlock) &LLVMValue; [extern] LLVMBuildIntCast2 = fn [cc(c)] (builder: &LLVMBuilder, value: &LLVMValue, type: &LLVMType, signed: s32, name: &u8) &LLVMValue; [extern] LLVMBuildNeg = fn [cc(c)] (builder: &LLVMBuilder, value: &LLVMValue, name: &u8) &LLVMValue; @@ -2094,28 +2188,41 @@ LLVMICmpPredicate = enum u32 [extern] LLVMBuildSRem = fn [cc(c)] (builder: &LLVMBuilder, left: &LLVMValue, right: &LLVMValue, name: &u8) &LLVMValue; [extern] LLVMBuildURem = fn [cc(c)] (builder: &LLVMBuilder, left: &LLVMValue, right: &LLVMValue, name: &u8) &LLVMValue; +[extern] LLVMBuildCall2 = fn [cc(c)] (builder: &LLVMBuilder, function_type: &LLVMType, function_value: &LLVMValue, argument_pointer: &&LLVMValue, argument_count: u32, name: &u8) &LLVMValue; + [extern] LLVMGetInsertBlock = fn [cc(c)] (builder: &LLVMBuilder) &LLVMBasicBlock; [extern] LLVMGetBasicBlockTerminator = fn [cc(c)] (basic_block: &LLVMBasicBlock) &LLVMValue; [extern] LLVMGetBasicBlockParent = fn [cc(c)] (basic_block: &LLVMBasicBlock) &LLVMValue; +[extern] LLVMConstNull = fn [cc(c)] (type: &LLVMType) &LLVMValue; [extern] LLVMConstInt = fn [cc(c)] (type: &LLVMType, value: u64, is_signed: s32) &LLVMValue; [extern] LLVMConstNeg = fn [cc(c)] (value: &LLVMValue) &LLVMValue; +[extern] LLVMConstArray2 = fn [cc(c)] (element_type: &LLVMType, value_pointer: &&LLVMValue, value_count: u64) &LLVMValue; [extern] LLVMInstructionEraseFromParent = fn [cc(c)] (value: &LLVMValue) void; [extern] LLVMGetOperand = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMValue; [extern] LLVMGetFirstUse = fn [cc(c)] (value: &LLVMValue) &LLVMUse; [extern] LLVMGetNextUse = fn [cc(c)] (use: &LLVMUse) &LLVMUse; [extern] LLVMGetUser = fn [cc(c)] (use: &LLVMUse) &LLVMValue; +[extern] LLVMGetFirstInstruction = fn [cc(c)] (basic_block: &LLVMBasicBlock) &LLVMValue; +[extern] LLVMReplaceAllUsesWith = fn [cc(c)] (old_value: &LLVMValue, new_value: &LLVMValue) void; + +[extern] LLVMDeleteBasicBlock = fn [cc(c)] (basic_block: &LLVMBasicBlock) void; [extern] LLVMIsABranchInst = fn [cc(c)] (value: &LLVMValue) &LLVMValue; [extern] LLVMIsConditional = fn [cc(c)] (value: &LLVMValue) s32; [extern] LLVMGetSuccessor = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMBasicBlock; -[extern] LLVMSetAlignment = fn [cc(c)] (value: &LLVMValue, alignment: u32) void; - [extern] llvm_find_return_value_dominating_store = fn [cc(c)] (builder: &LLVMBuilder, return_alloca: &LLVMValue, element_type: &LLVMType) &LLVMValue; -[extern] llvm_module_verify = fn [cc(c)] (module: &LLVMModule, error_message: &[]u8) u1; -[extern] llvm_module_to_string = fn [cc(c)] (module: &LLVMModule) []u8; + +[extern] LLVMVerifyModule = fn [cc(c)] (module: &LLVMModule, action: LLVMVerifyFailureAction, message_pointer: &&u8) s32; +[extern] LLVMPrintModuleToString = fn [cc(c)] (module: &LLVMModule) &u8; + +llvm_module_to_string = fn (module: &LLVMModule) []u8 +{ + >module_string = c_string_to_slice(LLVMPrintModuleToString(module)); + return module_string; +} [extern] LLVMCreateTargetMachineOptions = fn [cc(c)] () &LLVMTargetMachineOptions; [extern] LLVMTargetMachineOptionsSetCPU = fn [cc(c)] (target_machine_options: &LLVMTargetMachineOptions, cpu: &u8) void; @@ -2127,8 +2234,19 @@ LLVMICmpPredicate = enum u32 [extern] LLVMSetModuleDataLayout = fn [cc(c)] (module: &LLVMModule, target_data_layout: &LLVMTargetDataLayout) void; [extern] LLVMSetTarget = fn [cc(c)] (module: &LLVMModule, target_triple: &u8) void; -[extern] llvm_module_create_function = fn [cc(c)] (module: &LLVMModule, function_type: &LLVMType, linkage_type: LLVMLinkage, address_space: u32, name: []u8) &LLVMValue; +[extern] LLVMAddFunction = fn [cc(c)] (module: &LLVMModule, name: &u8, function_type: &LLVMType) &LLVMValue; +[extern] LLVMSetLinkage = fn [cc(c)] (value: &LLVMValue, linkage_type: LLVMLinkage) void; + +llvm_module_create_function = fn (module: &LLVMModule, function_type: &LLVMType, linkage_type: LLVMLinkage, name: []u8) &LLVMValue +{ + assert(name.pointer[name.length] == 0); + >function = LLVMAddFunction(module, name.pointer, function_type); + LLVMSetLinkage(function, linkage_type); + return function; +} + [extern] LLVMSetFunctionCallConv = fn [cc(c)] (function: &LLVMValue, calling_convention: LLVMCallingConvention) void; +[extern] LLVMSetInstructionCallConv = fn [cc(c)] (call: &LLVMValue, calling_convention: LLVMCallingConvention) void; [extern] llvm_module_run_optimization_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMOptimizationOptions) void; [extern] llvm_module_run_code_generation_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMCodeGenerationOptions) LLVMCodeGenerationResult; @@ -2321,8 +2439,19 @@ Statement = struct scope_to_block = fn (scope: &Scope) &Block { assert(scope.kind == .local); - >result: &Block = #field_parent_pointer(scope, "scope"); - return result; + return #field_parent_pointer(scope, "scope"); +} + +scope_to_function = fn (scope: &Scope) &ValueFunction +{ + assert(scope.kind == .function); + return #field_parent_pointer(scope, "scope"); +} + +scope_to_module = fn (scope: &Scope) &Module +{ + assert(scope.kind == .global); + return #field_parent_pointer(scope, "scope"); } new_local = fn (module: &Module, scope: &Scope) &Local @@ -2482,6 +2611,111 @@ get_pointer_type = fn (module: &Module, element_type: &Type) &Type return result; } +left_bracket: u8 = '['; +right_bracket: u8 = ']'; +left_parenthesis: u8 = '('; +right_parenthesis: u8 = ')'; +left_brace: u8 = '{'; +right_brace: u8 = '}'; + +format_integer_decimal = fn (buffer: []u8, v: u64) u64 +{ + >byte_count: u64 = 0; + >value = v; + + if (value != 0) + { + >reverse_buffer: [64]u8 = undefined; + >reverse_index: u64 = 0; + + while (value != 0) + { + >digit_value: u8 = #truncate(value % 10); + >ascii_character = digit_value + '0'; + value /= 10; + reverse_buffer[reverse_index] = ascii_character; + reverse_index += 1; + } + + while (reverse_index != 0) + { + reverse_index -= 1; + buffer[byte_count] = reverse_buffer[reverse_index]; + byte_count += 1; + } + } + else + { + buffer[0] = '0'; + byte_count = 1; + } + + return byte_count; +} + +array_name = fn (module: &Module, element_type: &Type, element_count: u64) []u8 +{ + >buffer: [512]u8 = undefined; + >buffer_slice = buffer[..]; + + >i: u64 = 0; + + buffer[i] = left_bracket; + i += 1; + + i += format_integer_decimal(buffer_slice[i..], element_count); + + buffer[i] = right_bracket; + i += 1; + + >element_name = element_type.name; + memcpy(&buffer[i], element_name.pointer, element_name.length); + i += element_name.length; + + >name = arena_duplicate_string(module.arena, buffer_slice[..i]); + return name; +} + +get_array_type = fn (module: &Module, element_type: &Type, element_count: u64) &Type +{ + assert(element_type != zero); + assert(element_count != 0); + + >array_type = module.first_array_type; + + if (array_type != zero) + { + #trap(); + } + + >last_array_type = array_type; + + >result = new_type(module, { + .content = { + .array = { + .element_type = element_type, + .element_count = element_count, + zero, + }, + }, + .id = .array, + .name = array_name(module, element_type, element_count), + .scope = element_type.scope, + zero, + }); + + if (last_array_type != zero) + { + last_array_type.content.array.next = result; + } + else + { + module.first_array_type = result; + } + + return result; +} + is_space = fn (ch: u8) u1 { return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; @@ -2691,13 +2925,6 @@ FunctionTypeAttribute = enum cc, } -left_bracket: u8 = '['; -right_bracket: u8 = ']'; -left_parenthesis: u8 = '('; -right_parenthesis: u8 = ')'; -left_brace: u8 = '{'; -right_brace: u8 = '}'; - accumulate_decimal = fn(accumulator: u64, ch: u8) u64 { assert(is_decimal(ch)); @@ -2798,6 +3025,11 @@ TypeKeyword = enum enum_array, } +get_slice_type = fn (module: &Module, element_type: &Type) &Type +{ + #trap(); +} + parse_type = fn (module: &Module, scope: &Scope) &Type { >start_character = module.content[module.offset]; @@ -2901,6 +3133,69 @@ parse_type = fn (module: &Module, scope: &Scope) &Type } else if (start_character == left_bracket) { + module.offset += 1; + skip_space(module); + + >is_slice = consume_character_if_match(module, right_bracket); + if (is_slice) + { + skip_space(module); + >element_type = parse_type(module, scope); + >slice_type = get_slice_type(module, element_type); + return slice_type; + } + else + { + >checkpoint = get_checkpoint(module); + >length_inferred: u1 = 0; + if (consume_character_if_match(module, '_')) + { + skip_space(module); + length_inferred = consume_character_if_match(module, ']'); + } + + >length_value: &Value = zero; + >element_count: u64 = 0; + >resolved: u1 = 0; + + if (!length_inferred) + { + #trap(); + } + + skip_space(module); + + >element_type = parse_type(module, scope); + + if (length_inferred) + { + assert(!length_value); + >result = new_type(module, { + .content = { + .array = { + .element_type = element_type, + .element_count = 0, + zero, + }, + }, + .id = .array, + .name = "", + .scope = element_type.scope, + zero, + }); + return result; + } + else + { + if (!resolved) + { + report_error(); + } + + #trap(); + } + #trap(); + } #trap(); } else if (start_character == '#') @@ -3233,7 +3528,38 @@ tokenize = fn (module: &Module) Token }, '.' => { - #trap(); + >id: TokenId = undefined; + >next_ch = module.content[start_index + 1]; + switch (next_ch) + { + else => { id = .dot; }, + '&' => { id = .pointer_dereference; }, + '.' => + { + switch (module.content[start_index + 2]) + { + '.' => { id = .triple_dot; }, + else => { id = .double_dot; }, + } + }, + } + + >add: u64 = undefined; + + switch (id) + { + .dot => { add = 1; }, + .double_dot, .pointer_dereference => { add = 2; }, + .triple_dot => { add = 3; }, + else => { unreachable; }, + } + + module.offset += add; + + token = { + .id = id, + zero, + }; }, '"' => { @@ -3437,11 +3763,41 @@ reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: [ { .global => { - #trap(); + assert(module == scope_to_module(scope)); + + >global = module.first_global; + + while (global != zero) + { + if (string_equal(identifier, global.variable.name)) + { + variable = &global.variable; + break; + } + + global = global.next; + } + + >macro_declaration = module.first_macro_declaration; + + while (macro_declaration != zero) + { + #trap(); + } }, .function => { - #trap(); + assert(scope.parent != zero); + >function = scope_to_function(scope); + + for (&argument: function.arguments) + { + if (string_equal(identifier, argument.variable.name)) + { + variable = &argument.variable; + break; + } + } }, .local => { @@ -3689,7 +4045,70 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value }, .left_bracket => { - #trap(); + >element_count: u64 = 0; + >value_buffer: [64]&Value = undefined; + + skip_space(module); + + >checkpoint = get_checkpoint(module); + >is_aggregate_initialization: u1 = 0; + + if (consume_character_if_match(module, '.')) + { + >identifier = parse_identifier(module); + + skip_space(module); + is_aggregate_initialization = consume_character_if_match(module, '='); + + if (!is_aggregate_initialization) + { + if (!consume_character_if_match(module, ',')) + { + report_error(); + } + } + } + + set_checkpoint(module, checkpoint); + + if (is_aggregate_initialization) + { + #trap(); + } + else + { + while (1) + { + skip_space(module); + + if (consume_character_if_match(module, right_bracket)) + { + break; + } + + >value = parse_value(module, scope, zero); + value_buffer[element_count] = value; + element_count += 1; + + consume_character_if_match(module, ','); + } + + >values = arena_allocate_slice[&Value](module.arena, element_count); + memcpy(#pointer_cast(values.pointer), #pointer_cast(&value_buffer), element_count * #byte_size(&Value)); + + result = new_value(module); + + result.& = { + .content = { + .array_initialization = { + .values = values, + .is_constant = 0, // This is analyzed later + }, + }, + .id = .array_initialization, + zero, + }; + } }, .dot => { @@ -3804,6 +4223,41 @@ get_token_precedence = fn (token: Token) Precedence } } +parse_call_arguments = fn (module: &Module, scope: &Scope) []&Value +{ + >arguments: []&Value = zero; + + >argument_count: u64 = 0; + >argument_buffer: [64]&Value = undefined; + + while (1) + { + skip_space(module); + + if (consume_character_if_match(module, right_parenthesis)) + { + break; + } + + >argument = parse_value(module, scope, zero); + >argument_index = argument_count; + argument_buffer[argument_index] = argument; + + skip_space(module); + + consume_character_if_match(module, ','); + + argument_count += 1; + } + + if (argument_count != 0) + { + #trap(); + } + + return arguments; +} + parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value { >left = builder.left; @@ -3887,15 +4341,116 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value }, .pointer_dereference => { - #trap(); + result = new_value(module); + result.& = { + .content = { + .unary = { + .value = left, + .id = .dereference, + }, + }, + .id = .unary, + .kind = .right, + zero, + }; }, .left_parenthesis => { - #trap(); + result = new_value(module); + + switch (left.id) + { + .macro_reference => + { + #trap(); + }, + else => + { + >arguments = parse_call_arguments(module, scope); + result.& = { + .content = { + .call = { + .callable = left, + .arguments = arguments, + zero, + }, + }, + .id = .call, + .kind = .right, + zero, + }; + }, + } }, .left_bracket => { - #trap(); + skip_space(module); + + result = new_value(module); + + if (left.id == .macro_reference) + { + #trap(); + } + else + { + left.kind = .left; + + >start_value: &Value = zero; + >start = !(module.content[module.offset] == '.' and module.content[module.offset + 1] == '.'); + if (start) + { + start_value = parse_value(module, scope, zero); + } + + >is_array = consume_character_if_match(module, right_bracket); + + if (is_array) + { + if (!start_value) + { + report_error(); + } + + >index = start_value; + result.& = { + .content = { + .array_expression = { + .array_like = left, + .index = index, + }, + }, + .id = .array_expression, + .kind = builder.kind, + zero, + }; + } + else + { + expect_character(module, '.'); + expect_character(module, '.'); + + >end_value: &Value = zero; + + if (!consume_character_if_match(module, right_bracket)) + { + end_value = parse_value(module, scope, zero); + expect_character(module, right_bracket); + } + + result.& = { + .content = { + .slice_expression = { + .array_like = left, + .start = start_value, + .end = end_value, + }, + }, + .id = .slice_expression, + zero, + }; + } + } }, .dot => { @@ -3978,6 +4533,8 @@ StatementStartKeyword = enum continue, } +parse_block = fn (module: &Module, parent_scope: &Scope) &Block; + parse_statement = fn (module: &Module, scope: &Scope) &Statement { >require_semicolon: u1 = 1; @@ -4001,7 +4558,7 @@ parse_statement = fn (module: &Module, scope: &Scope) &Statement module.offset += 1; skip_space(module); - >local_name = parse_identifier(module); + >local_name = arena_duplicate_string(module.arena, parse_identifier(module)); skip_space(module); >local_type: &Type = zero; @@ -4038,12 +4595,19 @@ parse_statement = fn (module: &Module, scope: &Scope) &Statement }, '#' => { - statement.content.expression = parse_value(module, scope, zero); + statement.content = { + .expression = parse_value(module, scope, zero), + }; statement.id = .expression; }, left_brace => { - #trap(); + >block = parse_block(module, scope); + statement.content = { + .block = block, + }; + statement.id = .block; + require_semicolon = 0; }, else => { @@ -4073,7 +4637,51 @@ parse_statement = fn (module: &Module, scope: &Scope) &Statement }, .if => { - #trap(); + skip_space(module); + expect_character(module, left_parenthesis); + skip_space(module); + + >condition = parse_value(module, scope, zero); + + skip_space(module); + expect_character(module, right_parenthesis); + skip_space(module); + + >if_statement = parse_statement(module, scope); + + skip_space(module); + + >is_else: u1 = 0; + >else_statement: &Statement = zero; + + if (is_identifier_start(module.content[module.offset])) + { + >checkpoint = get_checkpoint(module); + >identifier = parse_identifier(module); + + is_else = string_equal(identifier, "else"); + + if (is_else) + { + skip_space(module); + else_statement = parse_statement(module, scope); + } + else + { + set_checkpoint(module, checkpoint); + } + } + + require_semicolon = 0; + + statement.content = { + .if = { + .condition = condition, + .if = if_statement, + .else = else_statement, + }, + }; + statement.id = .if; }, .for => { @@ -4229,7 +4837,7 @@ parse = fn (module: &Module) void skip_space(module); } - >global_name = parse_identifier(module); + >global_name = arena_duplicate_string(module.arena, parse_identifier(module)); >last_global = module.first_global; @@ -4400,7 +5008,7 @@ parse = fn (module: &Module) void >line = get_line(module); argument_line_buffer[semantic_argument_count] = line; - >argument_name = parse_identifier(module); + >argument_name = arena_duplicate_string(module.arena, parse_identifier(module)); semantic_argument_name_buffer[semantic_argument_count] = argument_name; skip_space(module); @@ -4566,6 +5174,19 @@ resolve_alias = fn (module: &Module, type: &Type) &Type result = get_pointer_type(module, resolved_element_type); } }, + .array => + { + >element_type = type.content.array.element_type; + >resolved_element_type = resolve_alias(module, element_type); + if (element_type == resolved_element_type) + { + result = type; + } + else + { + result = get_array_type(module, resolved_element_type, type.content.array.element_count); + } + }, else => { #trap(); @@ -4601,6 +5222,15 @@ resolve_type_in_place_abi = fn (module: &Module, type: &Type) void { result = module.llvm.pointer_type; }, + .array => + { + >element_type = type.content.array.element_type; + >element_count = type.content.array.element_count; + assert(element_count != 0); + resolve_type_in_place_memory(module, element_type); + >array_type = LLVMArrayType2(element_type.llvm.memory, element_count); + result = array_type; + }, else => { #trap(); @@ -4690,6 +5320,17 @@ resolve_type_in_place_debug = fn (module: &Module, type: &Type) void result = LLVMDIBuilderCreatePointerType(module.llvm.di_builder, element_type.llvm.debug, 64, 64, default_address_space, type.name.pointer, type.name.length); } }, + .array => + { + >element_type = type.content.array.element_type; + >element_count = type.content.array.element_count; + assert(element_count != 0); + resolve_type_in_place_debug(module, element_type); + + >bit_alignment = get_byte_alignment(type) * 8; + >array_type = LLVMDIBuilderCreateArrayType(module.llvm.di_builder, get_bit_size(type), bit_alignment, element_type.llvm.debug, zero, 0); + result = array_type; + }, else => { #trap(); @@ -5023,7 +5664,7 @@ add_value_attribute = fn (module: &Module, value: &LLVMValue, index: u32, add_ca AttributeBuildOptions = struct { - return_abi: AbiInformation, + return_abi: &AbiInformation, argument_abis: []AbiInformation, abi_argument_types: []&Type, abi_return_type: &Type, @@ -5032,7 +5673,7 @@ AttributeBuildOptions = struct emit_attributes = fn (module: &Module, value: &LLVMValue, add_callback: &LLVMAttributeCallback, options: AttributeBuildOptions) void { - >return_abi = &options.return_abi; + >return_abi = options.return_abi; >semantic_return_type = return_abi.semantic_type; resolve_type_in_place(module, semantic_return_type); >abi_return_type = options.abi_return_type; @@ -5172,7 +5813,7 @@ create_alloca = fn (module: &Module, options: AllocaOptions) &LLVMValue alignment = get_byte_alignment(abi_type); } - >alloca = llvm_builder_create_alloca(module.llvm.builder, abi_type.llvm.memory, default_address_space, alignment, options.name); + >alloca = llvm_create_alloca(module.llvm.builder, abi_type.llvm.memory, alignment, options.name); return alloca; } @@ -5294,7 +5935,15 @@ TypeAnalysis = struct indexing_type: &Type, must_be_constant: u1, } + analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysis: TypeAnalysis) void; +emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_constant: u1) void; + +analyze_value = fn (module: &Module, value: &Value, expected_type: &Type, type_kind: TypeKind, must_be_constant: u1) void +{ + analyze_type(module, value, expected_type, { .must_be_constant = must_be_constant, zero }); + emit_value(module, value, type_kind, must_be_constant); +} analyze_binary_type = fn (module: &Module, left: &Value, right: &Value, is_boolean: u1, expected_type: &Type, must_be_constant: u1) void { @@ -5488,7 +6137,17 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi }, .dereference => { - #trap(); + analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero }); + if (value.kind == .left) + { + report_error(); + } + >pointer_type = unary_value.type; + assert(pointer_type.id == .pointer); + >dereference_type = pointer_type.content.pointer.element_type; + + typecheck(module, expected_type, dereference_type); + value_type = dereference_type; }, .int_from_enum => { @@ -5533,6 +6192,24 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi typecheck(module, expected_type, value_type); }, + // TODO: this is the default case + .ampersand + => + { + >is_boolean = unary_is_boolean(unary_id); + if (is_boolean) + { + analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero }); + value_type = uint1(module); + } + else + { + analyze_type(module, unary_value, expected_type, { .must_be_constant = analysis.must_be_constant, zero }); + value_type = unary_value.type; + } + + typecheck(module, expected_type, value_type); + }, else => { // TODO @@ -5607,6 +6284,144 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi typecheck(module, expected_type, value_type); }, + .call => + { + >call = &value.content.call; + >callable = call.callable; + analyze_type(module, callable, zero, { .must_be_constant = analysis.must_be_constant, zero }); + + >function_type: &Type = zero; + + switch (callable.id) + { + .variable => + { + >variable = callable.content.variable; + >variable_type = variable.type; + + switch (variable_type.id) + { + .function => + { + function_type = variable_type; + }, + .pointer => + { + >element_type = resolve_alias(module, variable_type.content.pointer.element_type); + + switch (element_type.id) + { + .function => + { + function_type = element_type; + }, + else => { report_error(); }, + } + }, + else => + { + report_error(); + }, + } + }, + else => + { + report_error(); + }, + } + + assert(function_type != zero); + assert(function_type.id == .function); + call.function_type = function_type; + + >semantic_argument_types = function_type.content.function.base.semantic_argument_types; + >call_arguments = call.arguments; + + if (function_type.content.function.base.is_variable_argument) + { + if (call_arguments.length < semantic_argument_types.length) + { + report_error(); + } + } + else + { + if (call_arguments.length != semantic_argument_types.length) + { + report_error(); + } + } + + for (i: 0..semantic_argument_types.length) + { + >argument_type = semantic_argument_types[i]; + >call_argument = call_arguments[i]; + analyze_type(module, call_argument, argument_type, { .must_be_constant = analysis.must_be_constant, zero }); + check_types(module, argument_type, call_argument.type); + } + + for (i: semantic_argument_types.length..call_arguments.length) + { + >call_argument = call_arguments[i]; + analyze_type(module, call_argument, zero, { .must_be_constant = analysis.must_be_constant, zero }); + } + + >semantic_return_type = function_type.content.function.base.semantic_return_type; + + typecheck(module, expected_type, semantic_return_type); + value_type = semantic_return_type; + }, + .array_initialization => + { + >values = value.content.array_initialization.values; + + if (expected_type != zero) + { + if (expected_type.id != .array) + { + report_error(); + } + + >element_type = expected_type.content.array.element_type; + + if (expected_type.content.array.element_count == 0) + { + // TODO: use existing types? + >element_count = values.length; + expected_type.content.array.element_count = element_count; + assert(string_equal(expected_type.name, "")); + expected_type.name = array_name(module, element_type, element_count); + } + else + { + if (expected_type.content.array.element_count != values.length) + { + report_error(); + } + } + + >is_constant: u1 = 1; + + for (value: values) + { + analyze_type(module, value, element_type, { .must_be_constant = analysis.must_be_constant, zero }); + is_constant = is_constant and value_is_constant(value); + } + + value.content.array_initialization.is_constant = is_constant; + + if (value.kind == .left) // TODO: possible? + { + report_error(); + } + + value_type = expected_type; + } + else + { + #trap(); + } + }, else => { #trap(); @@ -5728,6 +6543,256 @@ emit_binary = fn (module: &Module, left: &LLVMValue, left_type: &Type, right: &L } } +type_is_abi_equal = fn (module: &Module, a: &Type, b: &Type) u1 +{ + resolve_type_in_place(module, a); + resolve_type_in_place(module, b); + + >result = a == b; + if (!result) + { + result = a.llvm.abi == b.llvm.abi; + } + + return result; +} + +emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type: &Type) &LLVMValue +{ + assert(value.id == .call); + + >call = &value.content.call; + + >raw_function_type = call.function_type; + >callable = call.callable; + >call_arguments = call.arguments; + + >llvm_callable: &LLVMValue = zero; + + switch (callable.id) + { + .variable => + { + >variable = callable.content.variable; + >variable_type = variable.type; + >llvm_value = variable.storage.llvm; + + switch (variable_type.id) + { + .pointer => + { + >element_type = resolve_alias(module, variable_type.content.pointer.element_type); + + switch (element_type.id) + { + .function => + { + llvm_callable = create_load(module, { + .type = get_pointer_type(module, raw_function_type), + .pointer = llvm_value, + zero, + }); + }, + else => { report_error(); }, + } + }, + .function => { llvm_callable = llvm_value; }, + } + }, + else => { report_error(); }, + } + + assert(llvm_callable != zero); + + >llvm_abi_argument_value_buffer: [64]&LLVMValue = undefined; + >llvm_abi_argument_type_buffer: [64]&LLVMType = undefined; + >abi_argument_type_buffer: [64]&Type = undefined; + >argument_abi_buffer: [64]AbiInformation = undefined; + >llvm_abi_argument_type_buffer_slice = llvm_abi_argument_type_buffer[..]; + >abi_argument_type_buffer_slice = abi_argument_type_buffer[..]; + + >abi_argument_count: u16 = 0; + + >uses_in_alloca: u1 = 0; + if (uses_in_alloca) + { + #trap(); + } + + >llvm_indirect_return_value: &LLVMValue = zero; + + >return_abi = &raw_function_type.content.function.abi.return_abi; + >return_abi_kind = return_abi.flags.kind; + + switch (return_abi_kind) + { + .indirect, + .in_alloca, + .coerce_and_expand, + => + { + #trap(); + }, + else => {}, + } + + >available_registers = raw_function_type.content.function.abi.available_registers; + >declaration_semantic_argument_types = raw_function_type.content.function.base.semantic_argument_types; + + for (call_argument_index: 0..call_arguments.length) + { + >is_named_argument = call_argument_index < declaration_semantic_argument_types.length; + >semantic_call_argument_value = call_arguments[call_argument_index]; + + >semantic_argument_type: &Type = undefined; + >argument_abi: AbiInformation = undefined; + + if (is_named_argument) + { + argument_abi = raw_function_type.content.function.abi.argument_abis[call_argument_index]; + semantic_argument_type = argument_abi.semantic_type; + } + else + { + #trap(); + } + + assert(semantic_argument_type != zero); + + resolve_type_in_place(module, semantic_argument_type); + + if (is_named_argument) + { + // TODO: better slice single statement + >llvm_abi_argument_types = llvm_abi_argument_type_buffer_slice[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)]; + >destination_abi_argument_types = abi_argument_type_buffer_slice[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)]; + >source_abi_argument_types = raw_function_type.content.function.abi.abi_argument_types[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)]; + + for (i: 0..argument_abi.abi_count) + { + llvm_abi_argument_types[i] = source_abi_argument_types[i].llvm.abi; + destination_abi_argument_types[i] = source_abi_argument_types[i]; + } + } + + argument_abi_buffer[call_argument_index] = argument_abi; + + if (argument_abi.padding.type != zero) + { + #trap(); + } + + assert(abi_argument_count == argument_abi.abi_start); + + switch (argument_abi.flags.kind) + { + .direct, + .extend, + => + { + #trap(); + }, + .indirect, + .indirect_aliased, + => + { + #trap(); + }, + .ignore => { unreachable; }, + else => { #trap(); }, // TODO + } + + // TODO: uncomment this + //assert(abi_argument_count == #extend(argument_abi.abi_start + argument_abi.abi_count)); + } + + >declaration_abi_argument_types = raw_function_type.content.function.abi.abi_argument_types; + + if (raw_function_type.content.function.base.is_variable_argument) + { + assert(declaration_abi_argument_types.length <= #extend(abi_argument_count)); + } + else + { + assert(declaration_abi_argument_types.length == #extend(abi_argument_count)); + } + + assert(raw_function_type.llvm.abi != zero); + + >llvm_call = LLVMBuildCall2(module.llvm.builder, raw_function_type.llvm.abi, llvm_callable, &llvm_abi_argument_value_buffer[0], #extend(abi_argument_count), ""); + >llvm_calling_convention: LLVMCallingConvention = undefined; + switch (raw_function_type.content.function.base.calling_convention) + { + .c => { llvm_calling_convention = .c; }, + } + + LLVMSetInstructionCallConv(llvm_call, llvm_calling_convention); + + >argument_abis = argument_abi_buffer[..call_arguments.length]; + + emit_attributes(module, llvm_call, &LLVMAddCallSiteAttribute, { + .return_abi = return_abi, + .argument_abis = argument_abis, + .abi_argument_types = abi_argument_type_buffer[..#extend(abi_argument_count)], + .abi_return_type = raw_function_type.content.function.abi.abi_return_type, + .attributes = zero, + }); + + switch (return_abi_kind) + { + .ignore => + { + assert(return_abi.semantic_type == noreturn_type(module) or return_abi.semantic_type == void_type(module)); + return llvm_call; + }, + .direct, + .extend, + => + { + >coerce_to_type = abi_get_coerce_to_type(return_abi); + + if (return_abi.attributes.direct.offset == 0 and type_is_abi_equal(module, return_abi.semantic_type, coerce_to_type)) + { + >evaluation_kind = get_evaluation_kind(coerce_to_type); + + switch (evaluation_kind) + { + .scalar => { return llvm_call; }, + .aggregate => {}, + .complex => { unreachable; }, + } + + #trap(); + } + + #trap(); + }, + .indirect => + { + assert(llvm_indirect_return_value != zero); + return llvm_indirect_return_value; + }, + else => { unreachable; }, + } +} + +emit_constant_array = fn (module: &Module, elements: []&Value, element_type: &Type) &LLVMValue +{ + >value_buffer: [64]&LLVMValue = undefined; + + resolve_type_in_place(module, element_type); + + for (i: 0..elements.length) + { + >v = elements[i]; + emit_value(module, v, .memory, 1); + value_buffer[i] = v.llvm; + } + + >constant_array = LLVMConstArray2(element_type.llvm.memory, &value_buffer[0], elements.length); + return constant_array; +} + emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_constant: u1) void { assert(value.type != zero); @@ -5826,6 +6891,35 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con llvm_value = LLVMBuildTrunc(module.llvm.builder, llvm_unary_value, destination_type, ""); }, + .ampersand => + { + assert(resolved_value_type == resolved_unary_type); + llvm_value = llvm_unary_value; + }, + .dereference => + { + switch (value.kind) + { + .right => + { + >pointer_type = unary_value.type; + assert(pointer_type.id == .pointer); + >child_type = resolve_alias(module, pointer_type.content.pointer.element_type); + assert(child_type == resolved_value_type); + >load = create_load(module, { + .type = child_type, + .pointer = unary_value.llvm, + .kind = type_kind, + zero, + }); + llvm_value = load; + }, + .left => + { + #trap(); + } + } + }, else => { #trap(); }, } }, @@ -5921,6 +7015,26 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con }, } }, + .call => + { + llvm_value = emit_call(module, value, zero, zero); + }, + .array_initialization => + { + >values = value.content.array_initialization.values; + + if (value.content.array_initialization.is_constant) + { + assert(value.kind == .right); + assert(resolved_value_type.id == .array); + >element_type = resolved_value_type.content.array.element_type; + llvm_value = emit_constant_array(module, values, element_type); + } + else + { + #trap(); + } + }, else => { #trap(); @@ -5966,7 +7080,30 @@ emit_assignment = fn (module: &Module, left_llvm: &LLVMValue, left_type: &Type, }, .aggregate => { - #trap(); + switch (right.id) + { + .array_initialization => + { + >values = right.content.array_initialization.values; + assert(resolved_value_type.id == .array); + >u64_type = uint64(module); + resolve_type_in_place(module, u64_type); + + if (right.content.array_initialization.is_constant) + { + emit_value(module, right, .memory, 0); + #trap(); + } + else + { + #trap(); + } + }, + else => + { + #trap(); + }, + } }, .complex => { @@ -6037,6 +7174,27 @@ emit_local = fn (module: &Module, local: &Local) void } } +emit_condition = fn (module: &Module, condition: &Value) &LLVMValue +{ + >llvm_condition = condition.llvm; + >condition_type = condition.type; + assert(llvm_condition != zero); + assert(condition_type != zero); + + assert(condition_type.id == .integer or condition_type.id == .pointer); + + if (!(condition_type.id == .integer and condition_type.content.integer.bit_count == 1)) + { + llvm_condition = LLVMBuildICmp(module.llvm.builder, .ne, llvm_condition, LLVMConstNull(condition_type.llvm.abi), ""); + } + + assert(llvm_condition != zero); + + return llvm_condition; +} + +analyze_block = fn (module: &Module, block: &Block) void; + analyze_statement = fn (module: &Module, scope: &Scope, statement: &Statement) void { >parent_function_global: &Global = undefined; @@ -6139,6 +7297,46 @@ analyze_statement = fn (module: &Module, scope: &Scope, statement: &Statement) v emit_local(module, local); emit_assignment(module, local.variable.storage.llvm, local.variable.storage.type, local.initial_value); }, + .if => + { + >condition = statement.content.if.condition; + >taken_statement = statement.content.if.if; + >not_taken_statement = statement.content.if.else; + + >taken_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "if.taken"); + >not_taken_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "if.not_taken"); + >exit_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "if.exit"); + + analyze_value(module, condition, zero, .abi, 0); + >llvm_condition = emit_condition(module, condition); + + LLVMBuildCondBr(module.llvm.builder, llvm_condition, taken_block, not_taken_block); + LLVMPositionBuilderAtEnd(module.llvm.builder, taken_block); + + analyze_statement(module, scope, taken_statement); + + if (LLVMGetInsertBlock(module.llvm.builder) != zero) + { + LLVMBuildBr(module.llvm.builder, exit_block); + } + + LLVMPositionBuilderAtEnd(module.llvm.builder, not_taken_block); + if (not_taken_statement != zero) + { + analyze_statement(module, scope, not_taken_statement); + } + + if (LLVMGetInsertBlock(module.llvm.builder) != zero) + { + LLVMBuildBr(module.llvm.builder, exit_block); + } + + LLVMPositionBuilderAtEnd(module.llvm.builder, exit_block); + }, + .block => + { + analyze_block(module, statement.content.block); + }, else => { #trap(); @@ -6179,20 +7377,6 @@ emit_block = fn (module: &Module, basic_block: &LLVMBasicBlock) void LLVMPositionBuilderAtEnd(module.llvm.builder, basic_block); } -type_is_abi_equal = fn (module: &Module, a: &Type, b: &Type) u1 -{ - resolve_type_in_place(module, a); - resolve_type_in_place(module, b); - - >result = a == b; - if (!result) - { - result = a.llvm.abi == b.llvm.abi; - } - - return result; -} - LLVMObjectGenerate = struct { path: []u8, @@ -6353,7 +7537,7 @@ emit = fn (module: &Module) void assert(!module.current_macro_declaration); llvm_initialize_targets(); >context = LLVMContextCreate(); - >m = llvm_context_create_module(context, module.name); + >m = LLVMModuleCreateWithNameInContext(module.name.pointer, context); >builder = LLVMCreateBuilderInContext(context); >di_builder: &LLVMDIBuilder = zero; @@ -6386,9 +7570,9 @@ emit = fn (module: &Module) void 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; + >target_triple: &u8 = zero; + >cpu_model: &u8 = zero; + >cpu_features: &u8 = zero; if (target_compare(module.target, target_get_native())) { @@ -6402,8 +7586,8 @@ emit = fn (module: &Module) void } >target_machine_options = LLVMCreateTargetMachineOptions(); - LLVMTargetMachineOptionsSetCPU(target_machine_options, cpu_model.pointer); - LLVMTargetMachineOptionsSetFeatures(target_machine_options, cpu_features.pointer); + LLVMTargetMachineOptionsSetCPU(target_machine_options, cpu_model); + LLVMTargetMachineOptionsSetFeatures(target_machine_options, cpu_features); >code_generation_optimization_level: LLVMCodeGenerationOptimizationLevel = undefined; switch (module.build_mode) @@ -6418,7 +7602,7 @@ emit = fn (module: &Module) void >target: &LLVMTarget = zero; >error_message: &u8 = zero; - >result = LLVMGetTargetFromTriple(target_triple.pointer, &target, &error_message); + >result = LLVMGetTargetFromTriple(target_triple, &target, &error_message); if (result != 0) { report_error(); @@ -6426,11 +7610,11 @@ emit = fn (module: &Module) void assert(!error_message); - >target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple.pointer, target_machine_options); + >target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple, target_machine_options); >target_data_layout = LLVMCreateTargetDataLayout(target_machine); LLVMSetModuleDataLayout(m, target_data_layout); - LLVMSetTarget(m, target_triple.pointer); + LLVMSetTarget(m, target_triple); module.llvm = { .context = context, @@ -6610,7 +7794,7 @@ emit = fn (module: &Module) void }, } - >llvm_function = llvm_module_create_function(module.llvm.module, llvm_function_type, llvm_linkage, default_address_space, global.variable.name); + >llvm_function = llvm_module_create_function(module.llvm.module, llvm_function_type, llvm_linkage, global.variable.name); global.variable.storage.llvm = llvm_function; >llvm_calling_convention: LLVMCallingConvention = undefined; switch (calling_convention) @@ -6624,7 +7808,7 @@ emit = fn (module: &Module) void LLVMSetFunctionCallConv(llvm_function, llvm_calling_convention); emit_attributes(module, llvm_function, &LLVMAddAttributeAtIndex, { - .return_abi = function_type.abi.return_abi, + .return_abi = &function_type.abi.return_abi, .argument_abis = function_type.abi.argument_abis, .abi_argument_types = function_type.abi.abi_argument_types, .abi_return_type = function_type.abi.abi_return_type, @@ -6705,8 +7889,8 @@ emit = fn (module: &Module) void >llvm_abi_arguments = llvm_abi_argument_buffer[..function_type.abi.abi_argument_types.length]; LLVMGetParams(llvm_function, &llvm_abi_argument_buffer[0]); - >entry_block = llvm_context_create_basic_block(module.llvm.context, "entry", llvm_function); - >return_block = llvm_context_create_basic_block(module.llvm.context, "return_block", llvm_function); + >entry_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "entry"); + >return_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "return_block"); function.content.function.llvm.return_block = return_block; LLVMPositionBuilderAtEnd(module.llvm.builder, entry_block); @@ -6773,7 +7957,15 @@ emit = fn (module: &Module) void if (current_basic_block) { assert(!LLVMGetBasicBlockTerminator(current_basic_block)); - #trap(); + if (!LLVMGetFirstInstruction(current_basic_block) or !LLVMGetFirstUse(#pointer_cast(current_basic_block))) + { + LLVMReplaceAllUsesWith(#pointer_cast(return_block), #pointer_cast(current_basic_block)); + LLVMDeleteBasicBlock(return_block); + } + else + { + #trap(); + } } else { @@ -6876,12 +8068,13 @@ emit = fn (module: &Module) void LLVMDIBuilderFinalize(module.llvm.di_builder); } - >verification_error_message: []u8 = zero; - if (!llvm_module_verify(module.llvm.module, &verification_error_message)) + >verification_error_message: &u8 = zero; + >verify_result = LLVMVerifyModule(module.llvm.module, .return, &verification_error_message) == 0; + if (!verify_result) { print(llvm_module_to_string(module.llvm.module)); print("\n==========================\nLLVM VERIFICATION ERROR\n==========================\n"); - print(verification_error_message); + print(c_string_to_slice(verification_error_message)); print("\n"); report_error(); } @@ -7184,6 +8377,15 @@ names: [_][]u8 = [ "extend", "integer_max", "integer_hex", + "basic_pointer", + "basic_call", + "basic_branch", + "basic_array", + "basic_enum", + "basic_slice", + "basic_string", + "basic_varargs", + "basic_while", ]; [export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32 diff --git a/src/emitter.cpp b/src/emitter.cpp index 2aba2c9..9a06871 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -1,6 +1,34 @@ #include #include +fn LLVMValueRef llvm_module_create_function(Arena* arena, LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, String name) +{ + assert(name.pointer[name.length] == 0); + auto function = LLVMAddFunction(module, (char*)name.pointer, function_type); + LLVMSetLinkage(function, linkage_type); + return function; +} + +fn LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMThreadLocalMode thread_local_mode, bool externally_initialized) +{ + assert(name.pointer[name.length] == 0); + auto global = LLVMAddGlobal(module, type, (char*)name.pointer); + LLVMSetGlobalConstant(global, is_constant); + LLVMSetLinkage(global, linkage_type); + LLVMSetInitializer(global, initial_value); + LLVMSetThreadLocalMode(global, thread_local_mode); + LLVMSetExternallyInitialized(global, externally_initialized); + return global; +} + +fn LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, u32 alignment, String name) +{ + assert(name.pointer[name.length] == 0); + auto alloca = LLVMBuildAlloca(b, type, (char*)name.pointer); + LLVMSetAlignment(alloca, alignment); + return alloca; +} + enum class EvaluationKind { scalar, @@ -106,9 +134,9 @@ fn u64 get_byte_allocation_size(Type* type) struct LLVMGlobal { - String host_triple; - String host_cpu_model; - String host_cpu_features; + char* host_triple; + char* host_cpu_model; + char* host_cpu_features; }; global_variable LLVMGlobal llvm_global; @@ -186,9 +214,9 @@ fn void llvm_initialize_all_raw() LLVMInitializeX86Disassembler(); llvm_global = { - .host_triple = llvm_default_target_triple(), - .host_cpu_model = llvm_host_cpu_name(), - .host_cpu_features = llvm_host_cpu_features(), + .host_triple = LLVMGetDefaultTargetTriple(), + .host_cpu_model = LLVMGetHostCPUName(), + .host_cpu_features = LLVMGetHostCPUFeatures(), }; } @@ -230,7 +258,8 @@ fn u64 integer_max_value(u32 bit_count, bool is_signed) fn void dump_module(Module* module) { - print(llvm_module_to_string(module->llvm.module)); + auto module_str = LLVMPrintModuleToString(module->llvm.module); + print(c_string_to_slice(module_str)); } fn LLVMCallConv llvm_calling_convention(CallingConvention calling_convention) @@ -250,7 +279,7 @@ fn void llvm_initialize(Module* module) llvm_initialize_all(); auto context = LLVMContextCreate(); - auto m = llvm_context_create_module(context, module->name); + auto m = LLVMModuleCreateWithNameInContext((char*)module->name.pointer, context); auto builder = LLVMCreateBuilderInContext(context); LLVMDIBuilderRef di_builder = 0; @@ -279,9 +308,9 @@ fn void llvm_initialize(Module* module) module->scope.llvm = di_compile_unit; } - String target_triple = {}; - String cpu_model = {}; - String cpu_features = {}; + char* target_triple = {}; + char* cpu_model = {}; + char* cpu_features = {}; if (target_compare(module->target, target_get_native())) { @@ -296,8 +325,8 @@ fn void llvm_initialize(Module* module) } auto target_machine_options = LLVMCreateTargetMachineOptions(); - LLVMTargetMachineOptionsSetCPU(target_machine_options, (char*)cpu_model.pointer); - LLVMTargetMachineOptionsSetFeatures(target_machine_options, (char*)cpu_features.pointer); + LLVMTargetMachineOptionsSetCPU(target_machine_options, cpu_model); + LLVMTargetMachineOptionsSetFeatures(target_machine_options, cpu_features); LLVMCodeGenOptLevel code_generation_optimization_level; switch (module->build_mode) @@ -324,18 +353,18 @@ fn void llvm_initialize(Module* module) LLVMTargetRef target = 0; char* error_message = 0; - auto result = LLVMGetTargetFromTriple((char*)target_triple.pointer, &target, &error_message); + auto result = LLVMGetTargetFromTriple(target_triple, &target, &error_message); if (result != 0) { report_error(); } assert(!error_message); - auto target_machine = LLVMCreateTargetMachineWithOptions(target, (char*)target_triple.pointer, target_machine_options); + auto target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple, target_machine_options); auto target_data = LLVMCreateTargetDataLayout(target_machine); LLVMSetModuleDataLayout(m, target_data); - LLVMSetTarget(m, (char*)target_triple.pointer); + LLVMSetTarget(m, target_triple); module->llvm = { .context = context, @@ -1005,7 +1034,8 @@ fn void resolve_type_in_place_debug(Module* module, Type* type) result = type->llvm.debug; if (!result) { - result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, 64, 64, 0, (char*)type->name.pointer, type->name.length); + u32 address_space = 0; + result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, get_bit_size(type), get_byte_alignment(type) * 8, address_space, (char*)type->name.pointer, type->name.length); } } break; case TypeId::array: @@ -1823,7 +1853,7 @@ fn LLVMValueRef create_alloca(Module* module, AllocaOptions options) alignment = get_byte_alignment(abi_type); } - auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, 0, alignment, options.name); + auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, alignment, options.name); return alloca; } @@ -2364,7 +2394,7 @@ fn Global* get_enum_name_array_global(Module* module, Type* enum_type) field.name, }; unsigned address_space = 0; - auto name_global = llvm_module_create_global_variable(module->llvm.module, LLVMArrayType2(u8_type->llvm.abi, field.name.length + null_terminate), is_constant, LLVMInternalLinkage, LLVMConstStringInContext2(module->llvm.context, (char*)field.name.pointer, field.name.length, false), arena_join_string(module->arena, array_to_slice(name_parts)), name_before, LLVMNotThreadLocal, address_space, false); + auto name_global = llvm_module_create_global_variable(module->llvm.module, LLVMArrayType2(u8_type->llvm.abi, field.name.length + null_terminate), is_constant, LLVMInternalLinkage, LLVMConstStringInContext2(module->llvm.context, (char*)field.name.pointer, field.name.length, false), arena_join_string(module->arena, array_to_slice(name_parts)), LLVMNotThreadLocal, false); name_before = name_global; LLVMValueRef constants[] = { name_global, @@ -2380,7 +2410,7 @@ fn Global* get_enum_name_array_global(Module* module, Type* enum_type) auto name_array_type = LLVMArrayType2(slice_type->llvm.abi, array_element_count); auto is_constant = true; unsigned address_space = 0; - auto name_array_variable = llvm_module_create_global_variable(module->llvm.module, name_array_type, is_constant, LLVMInternalLinkage, name_array, string_literal("name.array.enum"), name_before, LLVMNotThreadLocal, address_space, false); + auto name_array_variable = llvm_module_create_global_variable(module->llvm.module, name_array_type, is_constant, LLVMInternalLinkage, name_array, string_literal("name.array.enum"), LLVMNotThreadLocal, false); LLVMSetAlignment(name_array_variable, get_byte_alignment(slice_type)); LLVMSetUnnamedAddress(name_array_variable, LLVMGlobalUnnamedAddr); @@ -2896,13 +2926,13 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal enum_type->name, }; auto function_name = arena_join_string(module->arena, array_to_slice(name_parts)); - auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMInternalLinkage, 0, function_name); + auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMInternalLinkage, function_name); LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv); LLVMValueRef llvm_argument; LLVMGetParams(llvm_function, &llvm_argument); - auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("entry"), llvm_function); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry"); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); auto alloca = create_alloca(module, { @@ -2910,8 +2940,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal .name = string_literal("retval"), }); - auto* return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("return_block"), llvm_function); - auto* else_block = llvm_context_create_basic_block(module->llvm.context, string_literal("else_block"), llvm_function); + auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block"); + auto* else_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "else_block"); auto enum_fields = enum_type->enumerator.fields; @@ -2923,7 +2953,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal for (u64 i = 0; i < enum_fields.length; i += 1) { auto& field = enum_fields[i]; - auto* case_block = llvm_context_create_basic_block(module->llvm.context, string_literal("case_block"), llvm_function); + auto* case_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "case_block"); auto case_value = LLVMConstInt(backing_type, field.value, false); LLVMAddCase(switch_instruction, case_value, case_block); @@ -3231,6 +3261,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal if (expected_type->array.element_count == 0) { + // TODO: use existing types? expected_type->array.element_count = values.length; assert(expected_type->name.equal(string_literal(""))); expected_type->name = array_name(module, expected_type->array.element_type, expected_type->array.element_count); @@ -3988,7 +4019,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal enum_type->name, }; auto function_name = arena_join_string(module->arena, array_to_slice(name_parts)); - auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMInternalLinkage, 0, function_name); + auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMInternalLinkage, function_name); LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv); auto name_array_global = get_enum_name_array_global(module, enum_type); @@ -4006,19 +4037,18 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal auto value_array = LLVMConstArray2(enum_value_type, value_constant_buffer, array_element_count); auto value_array_variable_type = LLVMArrayType2(enum_value_type, array_element_count); auto is_constant = true; - LLVMValueRef before = 0; LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal; unsigned address_space = 0; auto externally_initialized = false; - auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, value_array_variable_type, is_constant, LLVMInternalLinkage, value_array, string_literal("value.array.enum"), before, thread_local_mode, address_space, externally_initialized); + auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, value_array_variable_type, is_constant, LLVMInternalLinkage, value_array, string_literal("value.array.enum"), thread_local_mode, externally_initialized); LLVMSetAlignment(value_array_variable, enum_alignment); LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr); - 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); - auto* loop_entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.entry"), llvm_function); - auto* loop_body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.body"), llvm_function); - auto* loop_exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.exit"), llvm_function); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry"); + auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block"); + auto* loop_entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.entry"); + auto* loop_body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.body"); + auto* loop_exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.exit"); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); @@ -4082,8 +4112,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal auto length_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, slice_length, element_length, ""); - auto* length_match_block = llvm_context_create_basic_block(module->llvm.context, string_literal("length.match"), llvm_function); - auto* length_mismatch_block = llvm_context_create_basic_block(module->llvm.context, string_literal("length.mismatch"), llvm_function); + auto* length_match_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "length.match"); + auto* length_mismatch_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "length.mismatch"); LLVMBuildCondBr(module->llvm.builder, length_comparison, length_match_block, length_mismatch_block); LLVMPositionBuilderAtEnd(module->llvm.builder, length_match_block); @@ -4103,7 +4133,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal u64_type->llvm.abi, }; auto llvm_function_type = LLVMFunctionType(s32_type->llvm.abi, arguments, array_length(arguments), false); - auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMExternalLinkage, address_space, string_literal("memcmp")); + auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMExternalLinkage, string_literal("memcmp")); memcmp = llvm_function; } @@ -4138,7 +4168,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal }; auto memcmp_return_result = LLVMBuildCall2(module->llvm.builder, LLVMGlobalGetValueType(memcmp), memcmp, memcmp_arguments, array_length(memcmp_arguments), ""); auto content_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, memcmp_return_result, LLVMConstNull(s32_type->llvm.abi), ""); - auto* content_match_block = llvm_context_create_basic_block(module->llvm.context, string_literal("content.match"), llvm_function); + auto* content_match_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "content.match"); LLVMBuildCondBr(module->llvm.builder, content_comparison, content_match_block, length_mismatch_block); LLVMPositionBuilderAtEnd(module->llvm.builder, content_match_block); @@ -4897,7 +4927,7 @@ fn SliceEmitResult emit_string_literal(Module* module, Value* value) LLVMThreadLocalMode tlm = LLVMNotThreadLocal; bool externally_initialized = false; unsigned address_space = 0; - auto global = llvm_module_create_global_variable(module->llvm.module, string_type, is_constant, LLVMInternalLinkage, constant_string, string_literal("conststring"), before, tlm, address_space, externally_initialized); + auto global = llvm_module_create_global_variable(module->llvm.module, string_type, is_constant, LLVMInternalLinkage, constant_string, string_literal("conststring"), tlm, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto slice_type = get_slice_type(module, u8_type); @@ -5081,11 +5111,6 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm, }); } - if (get_byte_size(semantic_argument_type) > 60 && argument_abi.flags.kind != AbiKind::indirect) - { - trap(); - } - resolve_type_in_place(module, semantic_argument_type); if (is_named_argument) @@ -5263,7 +5288,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm, u32 address_space = 0; bool externally_initialized = false; - auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), before, thread_local_mode, address_space, externally_initialized); + auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto alignment = get_byte_alignment(semantic_argument_type); @@ -5420,7 +5445,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm, u32 address_space = 0; bool externally_initialized = false; - auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), before, thread_local_mode, address_space, externally_initialized); + auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto alignment = get_byte_alignment(semantic_argument_type); @@ -5759,9 +5784,9 @@ fn LLVMValueRef emit_va_arg(Module* module, Value* value, LLVMValueRef left_llvm trap(); } - auto* in_reg_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.in_reg"), llvm_function); - auto* in_mem_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.in_mem"), llvm_function); - auto* end_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.end"), llvm_function); + auto* in_reg_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.in_reg"); + auto* in_mem_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.in_mem"); + auto* end_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.end"); LLVMBuildCondBr(module->llvm.builder, in_regs, in_reg_block, in_mem_block); emit_block(module, in_reg_block); @@ -6188,7 +6213,7 @@ fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type, u32 address_space = 0; bool externally_initialized = false; - auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), before, thread_local_mode, address_space, externally_initialized); + auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), thread_local_mode, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); @@ -6272,7 +6297,7 @@ fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type, unsigned address_space = 0; LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal; bool externally_initialized = false; - auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), before, thread_local_mode, address_space, externally_initialized); + auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), thread_local_mode, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); LLVMSetAlignment(global, alignment); LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, byte_size_value); @@ -6720,7 +6745,7 @@ fn void emit_macro_instantiation(Module* module, Value* value) module->llvm.inlined_at = caller_debug_location; auto llvm_function = current_function->variable.storage->llvm; - auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("macro.entry"), llvm_function); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "macro.entry"); LLVMBuildBr(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); @@ -6737,7 +6762,7 @@ fn void emit_macro_instantiation(Module* module, Value* value) assert(!macro_instantiation->return_alloca); macro_instantiation->return_alloca = return_alloca; - auto* return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("macro.return_block"), llvm_function); + auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "macro.return_block"); assert(!macro_instantiation->return_block); macro_instantiation->return_block = return_block; @@ -7070,7 +7095,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect auto array_type = resolved_value_type->pointer.element_type; assert(array_type->id == TypeId::array); resolve_type_in_place(module, array_type); - auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), 0, LLVMNotThreadLocal, 0, 0); + auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), LLVMNotThreadLocal, 0); auto alignment = get_byte_alignment(resolved_value_type); LLVMSetAlignment(value_array_variable, alignment); LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr); @@ -7112,8 +7137,8 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect auto llvm_function = module->current_function->variable.storage->llvm; assert(llvm_function); - auto* right_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.right"), llvm_function); - auto* end_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.end"), llvm_function); + auto* right_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.right"); + auto* end_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.end"); LLVMBasicBlockRef true_block; LLVMBasicBlockRef false_block; @@ -8030,13 +8055,13 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 } break; case StatementId::if_st: { - auto* taken_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.taken"), llvm_function); - auto* not_taken_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.not_taken"), llvm_function); - auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.exit"), llvm_function); + auto* taken_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.taken"); + auto* not_taken_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.not_taken"); + auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.exit"); auto condition = statement->if_st.condition; analyze_value(module, condition, 0, TypeKind::abi, false); - auto llvm_condition = emit_condition(module, statement->if_st.condition); + auto llvm_condition = emit_condition(module, condition); LLVMBuildCondBr(module->llvm.builder, llvm_condition, taken_block, not_taken_block); LLVMPositionBuilderAtEnd(module->llvm.builder, taken_block); @@ -8072,13 +8097,13 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 } break; case StatementId::while_st: { - auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.entry"), llvm_function); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.entry"); LLVMBuildBr(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); - auto body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.body"), llvm_function); - auto continue_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.continue"), llvm_function); - auto exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.exit"), llvm_function); + auto body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.body"); + auto continue_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.continue"); + auto exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.exit"); auto previous_continue_block = module->llvm.continue_block; auto previous_exit_block = module->llvm.exit_block; @@ -8125,12 +8150,12 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 LLVMBuildBr(module->llvm.builder, entry_block); - if (llvm_value_use_empty((LLVMValueRef)body_block)) + if (!LLVMGetFirstUse((LLVMValueRef)body_block)) { trap(); } - if (llvm_value_use_empty((LLVMValueRef)exit_block)) + if (!LLVMGetFirstUse((LLVMValueRef)exit_block)) { trap(); } @@ -8212,7 +8237,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 } break; case StatementId::switch_st: { - auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("switch.exit"), llvm_function); + auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "switch.exit"); auto discriminant = statement->switch_st.discriminant; auto clauses = statement->switch_st.clauses; @@ -8239,7 +8264,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 for (u64 i = 0; i < clauses.length; i += 1) { auto& clause = clauses[i]; - clause.basic_block = llvm_context_create_basic_block(module->llvm.context, clause.values.length == 0 ? string_literal("switch.else_case_block") : string_literal("switch.case_block"), llvm_function); + clause.basic_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, clause.values.length == 0 ? "switch.else_case_block" : "switch.case_block"); discriminant_case_count += clause.values.length; if (clause.values.length == 0) @@ -8300,7 +8325,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 } else { - else_block = llvm_context_create_basic_block(module->llvm.context, string_literal("switch.else_case_block"), llvm_function); + else_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "switch.else_case_block"); } auto switch_instruction = LLVMBuildSwitch(module->llvm.builder, discriminant->llvm, else_block, discriminant_case_count); @@ -8383,10 +8408,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 resolve_type_in_place(module, index_type); auto index_zero = LLVMConstNull(index_type->llvm.abi); - auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.entry"), llvm_function); - auto* body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.body"), llvm_function); - auto* continue_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.continue"), llvm_function); - auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.exit"), llvm_function); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.entry"); + auto* body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.body"); + auto* continue_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.continue"); + auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.exit"); auto previous_continue_block = module->llvm.continue_block; auto previous_exit_block = module->llvm.exit_block; @@ -8621,8 +8646,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3 LLVMValueRef indices[] = { body_index_load, }; + auto gep_type = aggregate_type->structure.fields[0].type->pointer.element_type; + resolve_type_in_place(module, gep_type); auto gep = create_gep(module, { - .type = aggregate_type->structure.fields[0].type->pointer.element_type->llvm.memory, + .type = gep_type->llvm.memory, .pointer = extract_pointer, .indices = array_to_slice(indices), }); @@ -9161,8 +9188,7 @@ void emit(Module* module) case Linkage::internal: llvm_linkage_type = LLVMInternalLinkage; break; case Linkage::external: llvm_linkage_type = LLVMExternalLinkage; 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); + auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, llvm_linkage_type, global->variable.name); global->variable.storage->llvm = llvm_function; LLVMCallConv cc; @@ -9248,7 +9274,7 @@ void emit(Module* module) unsigned address_space = 0; bool externally_initialized = false; - auto global_llvm = llvm_module_create_global_variable(module->llvm.module, global_type->llvm.memory, is_constant, linkage, global->variable.initial_value->llvm, global->variable.name, before, thread_local_mode, address_space, externally_initialized); + auto global_llvm = llvm_module_create_global_variable(module->llvm.module, global_type->llvm.memory, is_constant, linkage, global->variable.initial_value->llvm, global->variable.name, thread_local_mode, externally_initialized); auto alignment = get_byte_alignment(global_type); LLVMSetAlignment(global_llvm, alignment); global->variable.storage->llvm = global_llvm; @@ -9286,8 +9312,8 @@ void emit(Module* module) Slice llvm_abi_arguments = { .pointer = llvm_abi_argument_buffer, .length = function_type->abi.abi_argument_types.length }; LLVMGetParams(llvm_function, llvm_abi_argument_buffer); - 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); + auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry"); + auto return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block"); global->variable.storage->function.llvm.return_block = return_block; LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); @@ -9552,7 +9578,7 @@ void emit(Module* module) { assert(!LLVMGetBasicBlockTerminator(current_basic_block)); - if (llvm_basic_block_is_empty(current_basic_block) || llvm_value_use_empty((LLVMValueRef)current_basic_block)) + if (!LLVMGetFirstInstruction(current_basic_block) || !LLVMGetFirstUse((LLVMValueRef)current_basic_block)) { LLVMReplaceAllUsesWith((LLVMValueRef)return_block, (LLVMValueRef)current_basic_block); LLVMDeleteBasicBlock(return_block); @@ -9633,7 +9659,7 @@ void emit(Module* module) auto alloca = LLVMGetOperand(store, 1); assert(alloca == return_alloca); LLVMInstructionEraseFromParent(store); - assert(llvm_value_use_empty(alloca)); + assert(!LLVMGetFirstUse(alloca)); LLVMInstructionEraseFromParent(alloca); } else @@ -9689,12 +9715,13 @@ void emit(Module* module) LLVMDIBuilderFinalize(module->llvm.di_builder); } - String verification_error_message = {}; - if (!llvm_module_verify(module->llvm.module, &verification_error_message)) + char* verification_error_message = 0; + auto result = LLVMVerifyModule(module->llvm.module, LLVMReturnStatusAction, &verification_error_message) == 0; + if (!result) { dump_module(module); print(string_literal("\n==========================\nLLVM VERIFICATION ERROR\n==========================\n")); - print(verification_error_message); + print(c_string_to_slice(verification_error_message)); bb_fail(); } diff --git a/src/llvm.cpp b/src/llvm.cpp index 8520149..141fe49 100644 --- a/src/llvm.cpp +++ b/src/llvm.cpp @@ -26,83 +26,12 @@ #include "lld/Common/CommonLinkerContext.h" -fn llvm::StringRef string_ref(String string) -{ - return llvm::StringRef((char*)string.pointer, string.length); -} - -EXPORT LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name) -{ - auto module = new llvm::Module(string_ref(name), *llvm::unwrap(context)); - return wrap(module); -} - -EXPORT LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized) -{ - llvm::GlobalValue::LinkageTypes linkage; - switch (linkage_type) - { - case LLVMExternalLinkage: linkage = llvm::GlobalValue::ExternalLinkage; break; - case LLVMInternalLinkage: linkage = llvm::GlobalValue::InternalLinkage; break; - default: trap(); - } - - llvm::GlobalValue::ThreadLocalMode tlm; - switch (thread_local_mode) - { - case LLVMNotThreadLocal: tlm = llvm::GlobalValue::NotThreadLocal; break; - default: trap(); - } - auto* global = new llvm::GlobalVariable(*llvm::unwrap(module), llvm::unwrap(type), is_constant, linkage, llvm::unwrap(initial_value), string_ref(name), before ? llvm::unwrap(before) : 0, tlm, address_space, externally_initialized); - return wrap(global); -} - EXPORT void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type) { auto sp = llvm::unwrap(subprogram); sp->replaceType(llvm::unwrap(subroutine_type)); } -EXPORT LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name) -{ - llvm::GlobalValue::LinkageTypes llvm_linkage_type; - switch (linkage_type) - { - case LLVMExternalLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break; - case LLVMAvailableExternallyLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage; break; - case LLVMLinkOnceAnyLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage; break; - case LLVMLinkOnceODRLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage; break; - case LLVMWeakAnyLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakAnyLinkage; break; - case LLVMWeakODRLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakODRLinkage; break; - case LLVMAppendingLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AppendingLinkage; break; - case LLVMInternalLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::InternalLinkage; break; - case LLVMPrivateLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::PrivateLinkage; break; - case LLVMExternalWeakLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break; - case LLVMCommonLinkage: - llvm_linkage_type = llvm::GlobalValue::LinkageTypes::CommonLinkage; break; - default: - trap(); - } - auto* function = llvm::Function::Create(llvm::unwrap(function_type), llvm_linkage_type, address_space, string_ref(name), llvm::unwrap(module)); - return wrap(function); -} - -EXPORT LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function) -{ - auto* basic_block = llvm::BasicBlock::Create(*llvm::unwrap(context), string_ref(name), parent_function ? llvm::unwrap(parent_function) : 0); - return wrap(basic_block); -} - // If there are multiple uses of the return-value slot, just check // for something immediately preceding the IP. Sometimes this can // happen with how we generate implicit-returns; it can also happen @@ -169,142 +98,6 @@ EXPORT LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LL return wrap(store); } -EXPORT bool llvm_value_use_empty(LLVMValueRef value) -{ - return llvm::unwrap(value)->use_empty(); -} - -EXPORT bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block) -{ - return llvm::unwrap(basic_block)->empty(); -} - -EXPORT LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, unsigned address_space, u32 alignment, String name) -{ - auto& builder = *llvm::unwrap(b); - auto llvm_alignment = llvm::Align(alignment); - return wrap(builder.Insert(new llvm::AllocaInst(llvm::unwrap(type), address_space, 0, llvm_alignment), string_ref(name))); -} - -fn String stream_to_string(llvm::raw_string_ostream& stream) -{ - // No need to call stream.flush(); because it's string-based - stream.flush(); - - auto string = stream.str(); - auto length = string.length(); - - u8* result = 0; - if (length) - { - result = new u8[length + 1]; - memcpy(result, string.c_str(), length); - result[length] = 0; - } - - return String{ result, length }; -} - -EXPORT String llvm_function_to_string(llvm::Function& function) -{ - std::string 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(LLVMValueRef function_value, String* error_message) -{ - std::string message_buffer; - llvm::raw_string_ostream message_stream(message_buffer); - - auto& function = *llvm::unwrap(function_value); - bool result = verifyFunction(function, &message_stream); - *error_message = stream_to_string(message_stream); - - // We invert the condition because LLVM conventions are just stupid - return !result; -} - -EXPORT bool llvm_module_verify(LLVMModuleRef m, String* error_message) -{ - std::string message_buffer; - llvm::raw_string_ostream message_stream(message_buffer); - - 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(LLVMModuleRef module) -{ - std::string buffer; - llvm::raw_string_ostream stream(buffer); - llvm::unwrap(module)->print(stream, 0); - - return stream_to_string(stream); -} - -EXPORT String llvm_default_target_triple() -{ - auto triple = llvm::sys::getDefaultTargetTriple(); - auto length = triple.length(); - - u8* pointer = 0; - if (length) - { - pointer = new u8[length + 1]; - memcpy(pointer, triple.c_str(), length); - pointer[length] = 0; - } - - return { pointer, length }; -} - -EXPORT String llvm_host_cpu_name() -{ - auto cpu = llvm::sys::getHostCPUName(); - auto result = String { (u8*)cpu.data(), cpu.size() }; - assert(result.pointer[result.length] == 0); - return result; -} - -EXPORT String llvm_host_cpu_features() -{ - llvm::SubtargetFeatures Features; -#if LLVM_VERSION_MAJOR >= 19 - auto host_cpu_features = llvm::sys::getHostCPUFeatures(); -#else - StringMap host_cpu_features; - if (!sys::getHostCPUFeatures(host_cpu_features)) { - return {}; - } -#endif - - for (const auto &[Feature, IsEnabled] : host_cpu_features) - { - Features.AddFeature(Feature, IsEnabled); - } - - auto feature_string = Features.getString(); - auto length = feature_string.length(); - - u8* result = 0; - if (length) - { - result = new u8[length + 1]; - memcpy(result, feature_string.c_str(), length + 1); - result[length] = 0; - } - - return { result, length }; -} - EXPORT void llvm_module_run_optimization_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, BBLLVMOptimizationPipelineOptions options) { auto module = llvm::unwrap(m); @@ -423,7 +216,7 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli { std::error_code error_code; - stream = std::make_unique(string_ref(options->output_file_path), error_code, llvm::sys::fs::OF_None); + stream = std::make_unique(llvm::StringRef((char*)options->output_file_path.pointer, options->output_file_path.length), error_code, llvm::sys::fs::OF_None); if (error_code) { diff --git a/src/llvm.hpp b/src/llvm.hpp index f2faa1e..dafd084 100644 --- a/src/llvm.hpp +++ b/src/llvm.hpp @@ -117,33 +117,12 @@ enum class DwarfType HP_VAX_complex_float_d = 0x90, // D floating complex. }; - fn bool llvm_initialized = false; -extern "C" String llvm_default_target_triple(); -extern "C" String llvm_host_cpu_name(); -extern "C" String llvm_host_cpu_features(); - -extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name); - -extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name); - -extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function); - -extern "C" LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized); - -extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name); -extern "C" bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block); - 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" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type); -extern "C" String llvm_module_to_string(LLVMModuleRef module); - extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options); extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options); diff --git a/src/parser.cpp b/src/parser.cpp index 3a4a7d7..1c0d275 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -670,7 +670,7 @@ fn FunctionHeaderParsing parse_function_header(Module* module, Scope* scope, boo if (mandate_argument_names) { - argument_name = parse_identifier(module); + argument_name = arena_duplicate_string(module->arena, parse_identifier(module)); skip_space(module); @@ -2573,7 +2573,7 @@ fn Statement* parse_statement(Module* module, Scope* scope) module->offset += 1; skip_space(module); - auto local_name = parse_identifier(module); + auto local_name = arena_duplicate_string(module->arena, parse_identifier(module)); skip_space(module); Type* local_type = 0; @@ -2761,7 +2761,7 @@ fn Statement* parse_statement(Module* module, Scope* scope) if (is_identifier_start(module->content[module->offset])) { - auto local_name = parse_identifier(module); + auto local_name = arena_duplicate_string(module->arena, parse_identifier(module)); auto local = new_local(module, scope); *local = { .variable = { @@ -3217,7 +3217,7 @@ void parse(Module* module) skip_space(module); } - auto global_name = parse_identifier(module); + auto global_name = arena_duplicate_string(module->arena, parse_identifier(module)); Global* global_forward_declaration = 0; Global* last_global = module->first_global; @@ -3674,7 +3674,7 @@ void parse(Module* module) break; } - auto argument_name = parse_identifier(module); + auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module)); skip_space(module); @@ -3757,7 +3757,7 @@ void parse(Module* module) auto argument_line = get_line(module); auto argument_column = get_column(module); - auto argument_name = parse_identifier(module); + auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module)); skip_space(module); expect_character(module, ':');