diff --git a/src/compiler.bbb b/src/compiler.bbb index ace2f3d..445da61 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -101,6 +101,29 @@ assert = macro (ok: u1) void } } +ArgumentBuilder = struct +{ + buffer: [128]&u8, + count: u64, +} + +add_argument = fn (builder: &ArgumentBuilder, argument: []u8) void +{ + assert(argument.pointer[argument.length] == 0); + >index = builder.count; + assert(index < builder.buffer.length); + builder.buffer[index] = argument.pointer; + builder.count = index + 1; +} + +flush_arguments = fn (builder: &ArgumentBuilder) []&u8 +{ + >argument_count = builder.count; + assert(argument_count < builder.buffer.length); + builder.buffer[argument_count] = zero; + return builder.buffer[..argument_count]; +} + align_forward = fn (value: u64, alignment: u64) u64 { assert(alignment != 0); @@ -154,6 +177,22 @@ string_equal = fn(a: []u8, b: []u8) u1 return result; } +string_first_character = fn (string: []u8, character: u8) u64 +{ + >result = string_no_match; + + for (i: 0..string.length) + { + if (character == string[i]) + { + result = i; + break; + } + } + + return result; +} + string_last_character = fn(string: []u8, character: u8) u64 { >i = string.length; @@ -1533,6 +1572,10 @@ receives_type = fn (value: &Value) u1 return receives_type(left) and receives_type(right); }, + .unary_type => + { + return 1; // TODO: base on unary_type_id + }, else => { #trap(); @@ -1727,6 +1770,11 @@ get_byte_size = fn (type: &Type) u64 >result = element_size * element_count; return result; }, + .alias => + { + >result = get_byte_size(type.content.alias.type); + return result; + }, else => { #trap(); @@ -1820,6 +1868,15 @@ get_bit_size = fn (type: &Type) u64 >result = type.content.union.byte_size * 8; return result; }, + .enum_array => + { + >enum_type = type.content.enum_array.enum_type; + >element_type = type.content.enum_array.element_type; + >element_bit_size = get_byte_size(element_type) * 8; + assert(enum_type.id == .enum); + >element_count = enum_type.content.enum.fields.length; + return element_bit_size * element_count; + }, else => { #trap(); @@ -1876,6 +1933,10 @@ is_promotable_integer_type_for_abi = fn (type: &Type) u1 >backing_type = type.content.enum.backing_type; return is_promotable_integer_type_for_abi(backing_type); }, + .pointer => + { + return 0; + }, else => { #trap(); @@ -1927,6 +1988,7 @@ ValueId = enum string_to_enum, macro_instantiation, field_parent_pointer, + build_mode, } ValueConstantInteger = struct @@ -2295,6 +2357,18 @@ value_is_constant = fn (value: &Value) u1 { return 1; }, + .unary_type => + { + >unary_type_id = value.content.unary_type.id; + switch (unary_type_id) + { + .align_of, + .byte_size, + .integer_max, + => { return 1; }, + else => { unreachable; }, + } + }, else => { #trap(); @@ -3761,6 +3835,7 @@ TypeKeyword = enum void, noreturn, enum_array, + fn, } type_is_slice = fn (type: &Type) u1 @@ -4545,6 +4620,15 @@ parse_type = fn (module: &Module, scope: &Scope) &Type >enum_array_type = get_enum_array_type(module, enum_type, element_type); return enum_array_type; }, + .fn => + { + skip_space(module); + >mandate_argument_names: u1 = 0; + >function_header = parse_function_header(module, scope, mandate_argument_names); + >result = function_header.type; + return result; + }, + else => { unreachable; }, } } else @@ -5751,7 +5835,10 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value }, .build_mode => { - #trap(); + result.& = { + .id = .build_mode, + zero, + }; }, .field_parent_pointer => { @@ -5785,7 +5872,7 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value .left_bracket => { >element_count: u64 = 0; - >value_buffer: [64]&Value = undefined; + >value_buffer: [128]&Value = undefined; skip_space(module); @@ -5826,6 +5913,7 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value } >value = parse_value(module, scope, zero); + assert(element_count < value_buffer.length); value_buffer[element_count] = value; element_count += 1; @@ -5851,7 +5939,7 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value }, .dot => { - >identifier = parse_identifier(module); + >identifier = parse_name(module); result = new_value(module); result.& = { .content = { @@ -6565,7 +6653,12 @@ parse_statement = fn (module: &Module, scope: &Scope) &Statement }, .return => { - >return_value = parse_value(module, scope, zero); + >return_value: &Value = zero; + // TODO: make this better + if (module.content[module.offset] != ';') + { + return_value = parse_value(module, scope, zero); + } statement.content.return = return_value; statement.id = .return; }, @@ -8690,19 +8783,16 @@ get_member_at_offset = fn (struct_type: &Type, offset: u64) &Field >byte_size = get_byte_size(struct_type); if (byte_size > offset) { - >offset_it: u64 = 0; >fields = struct_type.content.struct.fields; for (&field: fields) { - if (offset_it > offset) + if (field.offset > offset) { break; } result = field; - assert(offset_it == field.offset); - offset_it = align_forward(offset_it + get_byte_size(field.type), #extend(get_byte_alignment(field.type))); } assert(result != zero); @@ -8922,7 +9012,11 @@ abi_system_v_get_indirect_result = fn (module: &Module, type: &Type, free_gpr: u { if (is_promotable_integer_type_for_abi(type)) { - #trap(); + return abi_system_v_get_extend({ + .semantic_type = type, + .sign = type_is_signed(type), + zero, + }); } else { @@ -10039,6 +10133,29 @@ clone_value = fn (module: &Module, scope: &Scope, old_value: &Value) &Value }, }; }, + .call => + { + >callable = clone_value(module, scope, old_value.content.call.callable); + >old_arguments = old_value.content.call.arguments; + >arguments = arena_allocate_slice[&Value](module.arena, old_arguments.length); + + for (i: 0..arguments.length) + { + arguments[i] = clone_value(module, scope, old_arguments[i]); + } + + result.content = { + .call = { + .callable = callable, + .arguments = arguments, + .function_type = old_value.content.call.function_type, + }, + }; + }, + .unary_type => + { + result.content = old_value.content; + }, else => { #trap(); @@ -10695,7 +10812,7 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi .unary_type => { >unary_type_id = value.content.unary_type.id; - >unary_type = value.content.unary_type.type; // TODO: call resolve_type + >unary_type = resolve_type(module, value.content.unary_type.type); value.content.unary_type.type = unary_type; if (unary_type_id == .enum_values) @@ -13320,7 +13437,14 @@ emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type { switch (value.kind) { - .right => { #trap(); }, + .right => + { + return create_load(module, { + .type = destination_type, + .pointer = destination_pointer, + zero, + }); + }, .left => { #trap(); }, } } @@ -13336,7 +13460,8 @@ emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type emit_constant_array = fn (module: &Module, elements: []&Value, element_type: &Type) &LLVMValue { - >value_buffer: [64]&LLVMValue = undefined; + >value_buffer: [128]&LLVMValue = undefined; + assert(elements.length <= value_buffer.length); resolve_type_in_place(module, element_type); @@ -13455,7 +13580,14 @@ emit_field_access = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, l if (left_llvm) { - #trap(); + assert(get_evaluation_kind(field_access.type) == .aggregate); + >alignment = get_byte_alignment(field_access.type); + + >u64_type = uint64(module); + resolve_type_in_place(module, u64_type); + + LLVMBuildMemCpy(module.llvm.builder, left_llvm, alignment, gep, alignment, LLVMConstInt(u64_type.llvm.abi, get_byte_size(field_access.type), 0)); + return gep; } else { @@ -14369,7 +14501,7 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con if (type_kind == .memory) { - #trap(); + llvm_value = memory_to_abi(module, llvm_value, boolean_type); } } else @@ -14909,6 +15041,7 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con >alloca = create_alloca(module, { .type = aggregate_type, + .name = "", zero, }); @@ -15047,7 +15180,33 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con } else { - #trap(); + llvm_value = LLVMConstNull(abi_type); + + for (&initialization_element: elements) + { + >value = initialization_element.value; + >name = initialization_element.name; + + >result_field: &Field = zero; + + for (&field: fields) + { + if (string_equal(name, field.name)) + { + result_field = field; + break; + } + } + + assert(result_field != zero); + + emit_value(module, value, .memory, must_be_constant); + + >extended = LLVMBuildZExt(module.llvm.builder, value.llvm, abi_type, ""); + >shl = LLVMBuildShl(module.llvm.builder, extended, LLVMConstInt(abi_type, result_field.offset, 0), ""); + >or_value = LLVMBuildOr(module.llvm.builder, llvm_value, shl, ""); + llvm_value = or_value; + } } }, .enum_array => @@ -15222,6 +15381,10 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con }, } }, + .undefined => + { + llvm_value = LLVMGetPoison(get_llvm_type(resolved_value_type, type_kind)); + }, else => { #trap(); @@ -15581,6 +15744,21 @@ emit_assignment = fn (module: &Module, left_llvm: &LLVMValue, left_type: &Type, LLVMBuildMemCpy(module.llvm.builder, left_llvm, alignment, right.content.macro_instantiation.return_alloca, alignment, LLVMConstInt(u64_type.llvm.abi, size, 0)); }, + .field_access => + { + >value = emit_field_access(module, right, left_llvm, left_type, .memory); + right.llvm = value; + }, + .array_expression => + { + emit_value(module, right, .memory, 0); + create_store(module, { + .source = right.llvm, + .destination = left_llvm, + .type = resolved_value_type, + zero, + }); + }, else => { #trap(); @@ -15939,7 +16117,7 @@ analyze_statement = fn (module: &Module, scope: &Scope, statement: &Statement) v .range => { >start = value.content.range[0]; - >end = value.content.range[0]; + >end = value.content.range[1]; for (v: value.content.range) { @@ -16627,29 +16805,6 @@ generate_object = fn (module: &LLVMModule, target_machine: &LLVMTargetMachine, o return result; } -ArgumentBuilder = struct -{ - buffer: [128]&u8, - count: u64, -} - -add_argument = fn (builder: &ArgumentBuilder, argument: []u8) void -{ - assert(argument.pointer[argument.length] == 0); - >index = builder.count; - assert(index < builder.buffer.length); - builder.buffer[index] = argument.pointer; - builder.count = index + 1; -} - -flush_arguments = fn (builder: &ArgumentBuilder) []&u8 -{ - >argument_count = builder.count; - assert(argument_count < builder.buffer.length); - builder.buffer[argument_count] = zero; - return builder.buffer[..argument_count]; -} - link = fn (module: &Module) void { >arena = module.arena; @@ -17550,7 +17705,7 @@ emit = fn (module: &Module) void >semantic_return_type = return_abi.semantic_type; if (semantic_return_type == noreturn_type(module) or function.content.function.attributes.naked) { -#trap(); + LLVMBuildUnreachable(module.llvm.builder); } else if (semantic_return_type == void_type(module)) { @@ -17824,7 +17979,7 @@ compile = fn (arena: &Arena, options: CompileOptions) void emit(&module); } -compile_file = fn (arena: &Arena, compile_options: CompileFile) []u8 +compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8 { >relative_file_path = compile_options.relative_file_path; if (relative_file_path.length < 5) @@ -17901,7 +18056,113 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) []u8 if (is_compiler) { - #trap(); + >builder: ArgumentBuilder = zero; + + add_argument(&builder, "/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release/bin/llvm-config"); + add_argument(&builder, "--libdir"); + add_argument(&builder, "--libs"); + add_argument(&builder, "--system-libs"); + + >arguments = flush_arguments(&builder); + + >llvm_config = os_execute(arena, arguments, envp, { + .policies = [ .pipe, .ignore ], + zero, + }); + + >success = llvm_config.termination_kind == .exit and llvm_config.termination_code == 0; + + if (!success) + { + report_error(); + } + + >stream = llvm_config.streams[0]; + + >line = string_first_character(stream, '\n'); + + if (line == string_no_match) + { + report_error(); + } + + library_directory = stream[..line]; + library_directories = { .pointer = &library_directory, .length = 1 }; + + stream = stream[line + 1..]; + + line = string_first_character(stream, '\n'); + if (line == string_no_match) + { + report_error(); + } + + >llvm_library_stream = stream[..line]; + + stream = stream[line + 1..]; + + >library_count: u64 = 0; + + while (1) + { + >space = string_first_character(llvm_library_stream, ' '); + if (space == string_no_match) + { + >library_argument = llvm_library_stream; + library_buffer[library_count] = library_argument[2..]; + library_count += 1; + break; + } + + // Omit the first two characters: "-l" + >library_argument = llvm_library_stream[2..space]; + library_buffer[library_count] = library_argument; + library_count += 1; + llvm_library_stream = llvm_library_stream[space + 1..]; + } + + line = string_first_character(stream, '\n'); + if (line == string_no_match) + { + report_error(); + } + + assert(line == stream.length - 1); + + >system_library_stream = stream[..line]; + + while (1) + { + >space = string_first_character(system_library_stream, ' '); + if (space == string_no_match) + { + >library_argument = llvm_library_stream; + library_buffer[library_count] = library_argument[2..]; + library_count += 1; + break; + } + + // Omit the first two characters: "-l" + >library_argument = system_library_stream[2..space]; + library_buffer[library_count] = library_argument; + library_count += 1; + system_library_stream = system_library_stream[space + 1..]; + } + + library_buffer[library_count] = "gcc"; + library_count += 1; + + library_buffer[library_count] = "gcc_s"; + library_count += 1; + + library_buffer[library_count] = "lldCommon"; + library_count += 1; + + library_buffer[library_count] = "lldELF"; + library_count += 1; + + library_names = library_buffer[..library_count]; + library_paths = { .pointer = &llvm_bindings_library, .length = 1 }; } else if (string_equal(base_name, "c_abi")) { @@ -18125,7 +18386,7 @@ names: [_][]u8 = .build_mode = build_mode, .has_debug_info = has_debug_info, .silent = 0, - }); + }, envp); }, .test => { @@ -18149,7 +18410,7 @@ names: [_][]u8 = .build_mode = build_mode, .has_debug_info = has_debug_info, .silent = 1, - }); + }, envp); >arguments: [_]&u8 = [ executable_path.pointer, diff --git a/src/emitter.cpp b/src/emitter.cpp index dfcc596..564b2fa 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -686,20 +686,18 @@ fn Field* get_member_at_offset(Type* struct_type, u32 offset) if (struct_type->structure.byte_size > offset) { - u32 offset_it = 0; auto fields = struct_type->structure.fields; for (u64 i = 0; i < fields.length; i += 1) { auto* field = &fields[i]; - - if (offset_it > offset) + auto field_offset = field->offset; + if (field_offset > offset) { break; } result = field; - offset_it = (u32)align_forward(offset_it + get_byte_size(field->type), get_byte_alignment(field->type)); } assert(result);