From 230b41bd2ae18e46b00e70506292118526ab1011 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Sun, 8 Jun 2025 09:07:52 -0600 Subject: [PATCH] wip --- src/compiler.bbb | 1238 ++++++++++++++++++++++++++++++++++++++++++++-- src/emitter.cpp | 124 +++-- src/llvm.cpp | 83 ---- src/llvm.hpp | 33 +- src/parser.cpp | 2 +- 5 files changed, 1283 insertions(+), 197 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index b7e6b00..85b1bf6 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -847,7 +847,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 @@ -1315,11 +1316,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 +1426,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 +1445,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 +1466,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 +1537,11 @@ ValueId = enum variable, local, unary_type, + macro_reference, + call, + array_initialization, + array_expression, + slice_expression, } ValueConstantInteger = struct @@ -1673,6 +1701,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 +1735,10 @@ ValueContent = union binary: ValueBinary, variable: &Variable, unary_type: ValueUnaryType, + call: ValueCall, + array_initialization: ValueArrayInitialization, + array_expression: ValueArrayExpression, + slice_expression: ValueSliceExpression, } ValueKind = enum @@ -2017,13 +2075,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 +2091,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,6 +2115,7 @@ 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; @@ -2071,6 +2132,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,18 +2156,26 @@ 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; @@ -2129,6 +2199,7 @@ LLVMICmpPredicate = enum u32 [extern] llvm_module_create_function = fn [cc(c)] (module: &LLVMModule, function_type: &LLVMType, linkage_type: LLVMLinkage, address_space: u32, name: []u8) &LLVMValue; [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 +2392,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 +2564,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 +2878,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 +2978,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 +3086,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 +3481,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 +3716,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 +3998,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 +4176,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 +4294,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 +4486,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; @@ -4038,12 +4548,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 +4590,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 => { @@ -4566,6 +5127,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 +5175,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 +5273,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 +5617,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 +5626,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; @@ -5294,7 +5888,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 +6090,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 +6145,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 +6237,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 +6496,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 +6844,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 +6968,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 +7033,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 +7127,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 +7250,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 = llvm_context_create_basic_block(module.llvm.context, "if.taken", llvm_function); + >not_taken_block = llvm_context_create_basic_block(module.llvm.context, "if.not_taken", llvm_function); + >exit_block = llvm_context_create_basic_block(module.llvm.context, "if.exit", llvm_function); + + 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 +7330,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 +7490,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; @@ -6624,7 +7761,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, @@ -6773,7 +7910,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 { @@ -7184,6 +8329,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..d666ec9 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -250,7 +250,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; @@ -1823,7 +1823,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 +2364,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->arena, 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, address_space, false); name_before = name_global; LLVMValueRef constants[] = { name_global, @@ -2380,7 +2380,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->arena, module->llvm.module, name_array_type, is_constant, LLVMInternalLinkage, name_array, string_literal("name.array.enum"), LLVMNotThreadLocal, address_space, false); LLVMSetAlignment(name_array_variable, get_byte_alignment(slice_type)); LLVMSetUnnamedAddress(name_array_variable, LLVMGlobalUnnamedAddr); @@ -2896,13 +2896,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 +2910,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 +2923,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 +3231,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 +3989,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 +4007,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->arena, module->llvm.module, value_array_variable_type, is_constant, LLVMInternalLinkage, value_array, string_literal("value.array.enum"), thread_local_mode, address_space, 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 +4082,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 +4103,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 +4138,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 +4897,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->arena, module->llvm.module, string_type, is_constant, LLVMInternalLinkage, constant_string, string_literal("conststring"), tlm, address_space, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto slice_type = get_slice_type(module, u8_type); @@ -5081,11 +5081,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 +5258,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->arena, module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, address_space, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto alignment = get_byte_alignment(semantic_argument_type); @@ -5420,7 +5415,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->arena, module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, address_space, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); auto alignment = get_byte_alignment(semantic_argument_type); @@ -5759,9 +5754,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 +6183,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->arena, module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), thread_local_mode, address_space, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); @@ -6272,7 +6267,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->arena, module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), thread_local_mode, address_space, externally_initialized); LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr); LLVMSetAlignment(global, alignment); LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, byte_size_value); @@ -6720,7 +6715,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 +6732,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 +7065,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->arena, module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), LLVMNotThreadLocal, 0, 0); auto alignment = get_byte_alignment(resolved_value_type); LLVMSetAlignment(value_array_variable, alignment); LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr); @@ -7112,8 +7107,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 +8025,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 +8067,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 +8120,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 +8207,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 +8234,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 +8295,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 +8378,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 +8616,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 +9158,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 +9244,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->arena, module->llvm.module, global_type->llvm.memory, is_constant, linkage, global->variable.initial_value->llvm, global->variable.name, thread_local_mode, address_space, externally_initialized); auto alignment = get_byte_alignment(global_type); LLVMSetAlignment(global_llvm, alignment); global->variable.storage->llvm = global_llvm; @@ -9286,8 +9282,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 +9548,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 +9629,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 diff --git a/src/llvm.cpp b/src/llvm.cpp index 8520149..253577d 100644 --- a/src/llvm.cpp +++ b/src/llvm.cpp @@ -31,78 +31,12 @@ 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,23 +103,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 diff --git a/src/llvm.hpp b/src/llvm.hpp index f2faa1e..16b8c23 100644 --- a/src/llvm.hpp +++ b/src/llvm.hpp @@ -126,17 +126,36 @@ 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); +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; +} -extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function); +fn LLVMValueRef llvm_module_create_global_variable(Arena* arena, LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized) +{ + assert(name.pointer[name.length] == 0); + auto default_address_space = 0; + auto global = LLVMAddGlobalInAddressSpace(module, type, (char*)name.pointer, default_address_space); + LLVMSetGlobalConstant(global, is_constant); + LLVMSetLinkage(global, linkage_type); + LLVMSetInitializer(global, initial_value); + LLVMSetThreadLocalMode(global, thread_local_mode); + LLVMSetExternallyInitialized(global, externally_initialized); + return global; +} -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); +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; +} 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); diff --git a/src/parser.cpp b/src/parser.cpp index 3a4a7d7..6d68554 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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;