From beb3af95fc5629221d6aa8e82d999f7d90566b30 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Fri, 28 Jun 2024 22:31:45 +0200 Subject: [PATCH] Some improvements and bug fixes --- bootstrap/main.cpp | 870 ++++++++++++++++++++++++++++++--------------- run.sh | 13 +- 2 files changed, 597 insertions(+), 286 deletions(-) diff --git a/bootstrap/main.cpp b/bootstrap/main.cpp index 9ecdbff..b92362a 100644 --- a/bootstrap/main.cpp +++ b/bootstrap/main.cpp @@ -72,7 +72,7 @@ extern "C" void* memset(void* dst, u8 n, u64 size) return dst; } -extern "C" int memcmp(const void* left, const void* right, u64 n) +fn int memcmp(const void* left, const void* right, u64 n) { const u8 *l=(const u8*)left, *r=(const u8*)right; for (; n && *l == *r; n--, l++, r++); @@ -138,26 +138,32 @@ struct Slice { return pointer + length; } + + forceinline void copy_in(Slice other) + { + assert(length == other.length); + memcpy(pointer, other.pointer, sizeof(T) * other.length); + } }; using String = Slice; #define strlit(s) String{ .pointer = (u8*)s, .length = sizeof(s) - 1, } #define ch_to_str(ch) String{ .pointer = &ch, .length = 1 } -global auto constexpr fnv_offset = 14695981039346656037ull; -global auto constexpr fnv_prime = 1099511628211ull; +// global auto constexpr fnv_offset = 14695981039346656037ull; +// global auto constexpr fnv_prime = 1099511628211ull; -fn Hash hash_bytes(String bytes) -{ - u64 result = fnv_offset; - for (u64 i = 0; i < bytes.length; i += 1) - { - result ^= bytes.pointer[i]; - result *= fnv_prime; - } - - return (Hash)result; -} +// fn Hash hash_bytes(String bytes) +// { +// u64 result = fnv_offset; +// for (u64 i = 0; i < bytes.length; i += 1) +// { +// result ^= bytes.pointer[i]; +// result *= fnv_prime; +// } +// +// return (Hash)result; +// } // fn forceinline long syscall0(long n) // { @@ -219,18 +225,18 @@ fn forceinline long syscall6(long n, long a1, long a2, long a3, long a4, long a5 return ret; } -fn u8 memeq(u8* a, u8* b, u64 size) -{ - for (u64 i = 0; i < size; i += 1) - { - if (a[i] != b[i]) - { - return 0; - } - } - - return 1; -} +// fn u8 memeq(u8* a, u8* b, u64 size) +// { +// for (u64 i = 0; i < size; i += 1) +// { +// if (a[i] != b[i]) +// { +// return 0; +// } +// } +// +// return 1; +// } enum class SyscallX86_64 : u64 { read = 0, @@ -645,10 +651,10 @@ fn ssize_t syscall_write(int fd, const void *buffer, size_t bytes) syscall_exit(1); } -fn void* reserve(u64 size, u8 huge_pages) +fn void* reserve(u64 size) { int protection_flags = PROT_NONE; - int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | (huge_pages ? MAP_HUGETLB : 0); + int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; void* result = syscall_mmap(0, size, protection_flags, map_flags, -1, 0); assert(result != MAP_FAILED); return result; @@ -683,7 +689,7 @@ struct Arena fn Arena* init(u64 reserved_size, u64 granularity, u64 initial_size) { assert(initial_size % granularity == 0); - Arena* arena = (Arena*)reserve(reserved_size, granularity != minimum_granularity); + Arena* arena = (Arena*)reserve(reserved_size); commit(arena, initial_size); *arena = { .reserved_size = reserved_size, @@ -787,11 +793,13 @@ struct PinnedArray { T* pointer; u32 length; - u32 committed; + u32 capacity; global constexpr auto granularity = page_size; global constexpr auto reserved_size = ((u64)GB(4) - granularity); + // static_assert(sizeof(T) % granularity == 0); + forceinline T& operator[](u32 index) { assert(index < length); @@ -804,6 +812,11 @@ struct PinnedArray generic_pinned_array_ensure_capacity(generic_array, additional, sizeof(T)); } + forceinline void clear() + { + length = 0; + } + forceinline Slice add_with_capacity(u32 additional) { auto generic_array = (PinnedArray*)(this); @@ -814,8 +827,6 @@ struct PinnedArray }; } -// generic_pinned_array_ensure_capacity(array, additional_T, size_of_T); -// u8* result = generic_pinned_array_add_with_capacity(array, additional_T, size_of_T); forceinline Slice add(u32 additional) { ensure_capacity(additional); @@ -823,10 +834,40 @@ struct PinnedArray return slice; } + forceinline Slice append(Slice items) + { + assert(items.length <= 0xffffffff); + auto slice = add(items.length); + slice.copy_in(items); + return slice; + } + forceinline T* add_one() { return add(1).pointer; } + + forceinline T* append_one(T item) + { + T* new_item = add_one(); + *new_item = item; + return new_item; + } + + forceinline T pop() + { + assert(length); + length -= 1; + return pointer[length]; + } + + forceinline Slice slice() + { + return { + .pointer = pointer, + .length = length, + }; + } }; forceinline fn u32 generic_pinned_array_length(PinnedArray* array, u32 size_of_T) @@ -837,26 +878,23 @@ forceinline fn u32 generic_pinned_array_length(PinnedArray* array, u32 size_ fn void generic_pinned_array_ensure_capacity(PinnedArray* array, u32 additional_T, u32 size_of_T) { - if (array->committed == 0) + u32 wanted_capacity = array->length + additional_T; + if (array->capacity < array->length + additional_T) { - assert(array->length == 0); - assert(array->pointer == 0); - array->pointer = static_cast(reserve(PinnedArray::reserved_size, 0)); - } + if (array->capacity == 0) + { + assert(array->length == 0); + assert(array->pointer == 0); + array->pointer = static_cast(reserve(PinnedArray::reserved_size)); + } - u32 additional_bytes = additional_T * size_of_T; - u32 current_length_bytes = generic_pinned_array_length(array, size_of_T); - u64 granularity_aligned_commit_bytes = align_forward(current_length_bytes, PinnedArray::granularity); - u64 new_length_bytes = current_length_bytes + additional_bytes; - - if (granularity_aligned_commit_bytes < new_length_bytes) - { - assert(new_length_bytes <= PinnedArray::reserved_size); - u64 new_granularity_aligned_commit_bytes = align_forward(new_length_bytes, PinnedArray::granularity); - u8* commit_pointer = array->pointer + granularity_aligned_commit_bytes; - u64 commit_bytes = new_granularity_aligned_commit_bytes + granularity_aligned_commit_bytes; - commit(commit_pointer, commit_bytes); - array->committed += commit_bytes / PinnedArray::granularity; + u64 currently_committed_size = align_forward(array->capacity * size_of_T, array->granularity); + u64 wanted_committed_size = align_forward(wanted_capacity * size_of_T, array->granularity); + void* commit_pointer = array->pointer + currently_committed_size; + u64 commit_size = wanted_committed_size - currently_committed_size; + assert(commit_size > 0); + commit(commit_pointer, commit_size); + array->capacity = wanted_committed_size / size_of_T; } } @@ -864,7 +902,7 @@ fn u8* generic_pinned_array_add_with_capacity(PinnedArray* array, u32 additi { u32 current_length_bytes = generic_pinned_array_length(array, size_of_T); assert(current_length_bytes < PinnedArray::reserved_size); - u8* pointer = array->pointer; + u8* pointer = array->pointer + current_length_bytes; array->length += additional_T; return pointer; } @@ -878,7 +916,7 @@ struct GetOrPut V* value; u8 existing; }; -fn GetOrPut generic_pinned_hashmap_get_or_put(PinnedHashmap* hashmap, u8* new_key_pointer, u32 key_size, u8* new_value_pointer, u32 value_size); +// fn GetOrPut generic_pinned_hashmap_get_or_put(PinnedHashmap* hashmap, u8* new_key_pointer, u32 key_size, u8* new_value_pointer, u32 value_size); template @@ -897,97 +935,97 @@ struct PinnedHashmap static_assert(granularity % sizeof(K) == 0, ""); static_assert(granularity % sizeof(V) == 0, ""); - forceinline GetOrPut get_or_put(K key, V value) - { - auto* generic_hashmap = (PinnedHashmap*)(this); - auto generic_get_or_put = generic_pinned_hashmap_get_or_put(generic_hashmap, (u8*)&key, sizeof(K), (u8*)&value, sizeof(V)); - return *(GetOrPut*)&generic_get_or_put; - } + // forceinline GetOrPut get_or_put(K key, V value) + // { + // auto* generic_hashmap = (PinnedHashmap*)(this); + // auto generic_get_or_put = generic_pinned_hashmap_get_or_put(generic_hashmap, (u8*)&key, sizeof(K), (u8*)&value, sizeof(V)); + // return *(GetOrPut*)&generic_get_or_put; + // } }; // Returns the generic value pointer if the key is present -fn u32 generic_pinned_hashmap_get_index(PinnedHashmap* hashmap, u8* key_pointer, u32 key_size) -{ - u32 index = hashmap->invalid_index; +// fn u32 generic_pinned_hashmap_get_index(PinnedHashmap* hashmap, u8* key_pointer, u32 key_size) +// { +// u32 index = hashmap->invalid_index; +// +// for (u32 i = 0; i < hashmap->length; i += 1) +// { +// u8* it_key_pointer = &hashmap->keys[i * key_size]; +// if (memeq(it_key_pointer, key_pointer, key_size)) +// { +// index = (it_key_pointer - hashmap->keys) / key_size; +// break; +// } +// } +// +// return index; +// } - for (u32 i = 0; i < hashmap->length; i += 1) - { - u8* it_key_pointer = &hashmap->keys[i * key_size]; - if (memeq(it_key_pointer, key_pointer, key_size)) - { - index = (it_key_pointer - hashmap->keys) / key_size; - break; - } - } +// fn void generic_pinned_hashmap_ensure_capacity(PinnedHashmap* hashmap, u32 key_size, u32 value_size, u32 additional_elements) +// { +// if (additional_elements != 0) +// { +// if (hashmap->key_page_capacity == 0) +// { +// assert(hashmap->value_page_capacity == 0); +// hashmap->keys = (u8*)reserve(hashmap->reserved_size); +// hashmap->values = (u8*)reserve(hashmap->reserved_size); +// } +// +// u32 target_element_capacity = hashmap->length + additional_elements; +// +// { +// u32 key_byte_capacity = hashmap->key_page_capacity * hashmap->granularity; +// u32 target_byte_capacity = target_element_capacity * key_size; +// if (key_byte_capacity < target_byte_capacity) +// { +// u32 aligned_target_byte_capacity = align_forward(target_byte_capacity, hashmap->granularity); +// void* commit_pointer = hashmap->keys + key_byte_capacity; +// u32 commit_size = aligned_target_byte_capacity - key_byte_capacity; +// commit(commit_pointer, commit_size); +// hashmap->key_page_capacity = aligned_target_byte_capacity / hashmap->granularity; +// } +// } +// +// { +// u32 value_byte_capacity = hashmap->value_page_capacity * hashmap->granularity; +// u32 target_byte_capacity = target_element_capacity * value_size; +// if (value_byte_capacity < target_byte_capacity) +// { +// u32 aligned_target_byte_capacity = align_forward(target_byte_capacity, hashmap->granularity); +// void* commit_pointer = hashmap->values + value_byte_capacity; +// u32 commit_size = aligned_target_byte_capacity - value_byte_capacity; +// commit(commit_pointer, commit_size); +// hashmap->value_page_capacity = aligned_target_byte_capacity / hashmap->granularity; +// } +// } +// } +// } - return index; -} - -fn void generic_pinned_hashmap_ensure_capacity(PinnedHashmap* hashmap, u32 key_size, u32 value_size, u32 additional_elements) -{ - if (additional_elements != 0) - { - if (hashmap->key_page_capacity == 0) - { - assert(hashmap->value_page_capacity == 0); - hashmap->keys = (u8*)reserve(hashmap->reserved_size, 0); - hashmap->values = (u8*)reserve(hashmap->reserved_size, 0); - } - - u32 target_element_capacity = hashmap->length + additional_elements; - - { - u32 key_byte_capacity = hashmap->key_page_capacity * hashmap->granularity; - u32 target_byte_capacity = target_element_capacity * key_size; - if (key_byte_capacity < target_byte_capacity) - { - u32 aligned_target_byte_capacity = align_forward(target_byte_capacity, hashmap->granularity); - void* commit_pointer = hashmap->keys + key_byte_capacity; - u32 commit_size = aligned_target_byte_capacity - key_byte_capacity; - commit(commit_pointer, commit_size); - hashmap->key_page_capacity = aligned_target_byte_capacity / hashmap->granularity; - } - } - - { - u32 value_byte_capacity = hashmap->value_page_capacity * hashmap->granularity; - u32 target_byte_capacity = target_element_capacity * value_size; - if (value_byte_capacity < target_byte_capacity) - { - u32 aligned_target_byte_capacity = align_forward(target_byte_capacity, hashmap->granularity); - void* commit_pointer = hashmap->values + value_byte_capacity; - u32 commit_size = aligned_target_byte_capacity - value_byte_capacity; - commit(commit_pointer, commit_size); - hashmap->value_page_capacity = aligned_target_byte_capacity / hashmap->granularity; - } - } - } -} - -fn GetOrPut generic_pinned_hashmap_get_or_put(PinnedHashmap* hashmap, u8* new_key_pointer, u32 key_size, u8* new_value_pointer, u32 value_size) -{ - u32 index = generic_pinned_hashmap_get_index(hashmap, new_key_pointer, key_size); - if (index != hashmap->invalid_index) - { - trap(); - } - else - { - generic_pinned_hashmap_ensure_capacity(hashmap, key_size, value_size, 1); - u32 new_index = hashmap->length; - hashmap->length += 1; - u8* key_pointer = &hashmap->keys[new_index * key_size]; - u8* value_pointer = &hashmap->values[new_index * value_size]; - memcpy(key_pointer, new_key_pointer, key_size); - memcpy(value_pointer, new_value_pointer, value_size); - - return { - .key = key_pointer, - .value = value_pointer, - .existing = 0, - }; - } -} +// fn GetOrPut generic_pinned_hashmap_get_or_put(PinnedHashmap* hashmap, u8* new_key_pointer, u32 key_size, u8* new_value_pointer, u32 value_size) +// { +// u32 index = generic_pinned_hashmap_get_index(hashmap, new_key_pointer, key_size); +// if (index != hashmap->invalid_index) +// { +// trap(); +// } +// else +// { +// generic_pinned_hashmap_ensure_capacity(hashmap, key_size, value_size, 1); +// u32 new_index = hashmap->length; +// hashmap->length += 1; +// u8* key_pointer = &hashmap->keys[new_index * key_size]; +// u8* value_pointer = &hashmap->values[new_index * value_size]; +// memcpy(key_pointer, new_key_pointer, key_size); +// memcpy(value_pointer, new_value_pointer, value_size); +// +// return { +// .key = key_pointer, +// .value = value_pointer, +// .existing = 0, +// }; +// } +// } typedef enum FileStatus { @@ -1049,7 +1087,8 @@ struct SemaType SemaTypeId id : type_id_bit_count; u32 resolved: 1; u32 flags: type_flags_bit_count; - u32 name; + u32 reserved; + String name; u8 get_bit_count() { @@ -1062,7 +1101,7 @@ struct SemaType } }; -static_assert(sizeof(SemaType) == sizeof(u64) * 3, "Type must be 24 bytes"); +static_assert(sizeof(SemaType) == sizeof(u64) * 5, "Type must be 24 bytes"); forceinline u8 Type::is_resolved() { return (id == Id::backend) | ((id == Id::sema) & get_sema()->resolved); @@ -1083,7 +1122,7 @@ struct Symbol external, }; - u32 name; + String name; Id id: 1; Linkage linkage: 1; }; @@ -1179,15 +1218,20 @@ global auto constexpr integer_type_offset = 5; global auto constexpr integer_type_count = 64 * 2; global auto constexpr builtin_type_count = integer_type_count + integer_type_offset + 1; +struct Thread +{ + Arena* arena; + Slice functions; +}; struct Unit { - PinnedArray files; - PinnedArray functions; - Arena* arena; - Arena* node_arena; - Arena* type_arena; - PinnedHashmap identifiers; + // PinnedArray files; + // PinnedArray functions; + // Arena* arena; + // Arena* node_arena; + // Arena* type_arena; + // PinnedHashmap identifiers; SemaType* builtin_types; u64 generate_debug_information : 1; @@ -1216,6 +1260,13 @@ struct ProjectionData NodeDataType type; u16 index; }; + +struct Output +{ + Node* node; + u16 slot; +}; + // This is a node in the "sea of nodes" sense: // https://en.wikipedia.org/wiki/Sea_of_nodes struct Node @@ -1230,11 +1281,13 @@ struct Node static_assert(sizeof(NodeDataType) <= 2); - Node** edges; + Node** inputs; + Output* outputs; u32 gvn; u16 input_count; + u16 input_capacity; u16 output_count; - u16 capacity; + u16 output_capacity; NodeDataType data_type; Id id; @@ -1250,117 +1303,229 @@ struct Node forceinline Slice get_inputs() { return { - .pointer = edges, + .pointer = inputs, .length = input_count, }; } - forceinline Slice get_outputs() + forceinline Slice get_outputs() { return { - .pointer = edges + input_count, + .pointer = outputs, .length = output_count, }; } - [[nodiscard]] fn Node* add(Unit* unit) + struct NodeData { - Node* node = unit->node_arena->allocate_one(); - *node = {}; + NodeDataType type; + u16 input_count; + Id id; + }; + + struct DynamicNodeData + { + NodeData s; + u32 gvn; + u16 input_capacity; + }; + + [[nodiscard]] fn Node* add(Arena* arena, DynamicNodeData data) + { + auto* node = arena->allocate_one(); + u16 output_count = 0; + u16 output_capacity = 4; + *node = { + .inputs = arena->allocate_many(data.input_capacity), + .outputs = arena->allocate_many(output_capacity), + .gvn = data.gvn, + .input_count = data.s.input_count, + .input_capacity = data.input_capacity, + .output_count = output_count, + .output_capacity = output_capacity, + .data_type = data.s.type, + .id = data.s.id, + }; + + memset(node->inputs, 0, sizeof(Node*) * node->input_capacity); + memset(node->outputs, 0, sizeof(Output) * node->output_capacity); + return node; } - [[nodiscard]] fn Node* add_from_function(Unit* unit, Function* function) + [[nodiscard]] fn Node* add_from_function_dynamic(Arena* arena, Function* function, NodeData data, u16 input_capacity) { - u32 gvn = function->node_count; + auto gvn = function->node_count; function->node_count += 1; - Node* node = unit->node_arena->allocate_one(); - *node = { + + auto* node = add(arena, { + .s = data, .gvn = gvn, - }; + .input_capacity = input_capacity, + }); return node; } + + [[nodiscard]] fn Node* add_from_function(Arena* arena, Function* function, NodeData data) + { + return add_from_function_dynamic(arena, function, data, data.input_count); + } - Node* project(Unit* unit, Function* function, ProjectionData data) + [[nodiscard]] Node* project(Arena* arena, Function* function, ProjectionData data) { assert(data_type.id == NodeDataType::Id::TUPLE); - Node* projection = Node::add_from_function(unit, function); + Node* projection = Node::add_from_function(arena, function, { + .input_count = 1, + }); assert(projection != this); projection->id = Node::Id::PROJECTION; projection->data_type = data.type; - projection->reallocate_edges(unit, 4); + // projection->reallocate_edges(unit, 4); projection->input_count = 1; - projection->set_input(unit, function, this, 0); + projection->set_input(this, 0); projection->projection.index = data.index; return projection; } - void set_input(Unit* unit, Function* function, Node* input, u16 slot) + void set_input(Node* input, u16 slot) { assert(slot < input_count); - remove_output(unit, function, slot); - *get_input_slot(slot) = input; + remove_output(slot); + inputs[slot] = input; if (input) { - add_output(unit, function, input); + add_output(input, slot); } } - Node** get_output_slot(u16 slot) + void add_output(Node* input, u16 slot) { - assert(slot < output_count); - return edges + input_count + slot; - } - - Node** get_input_slot(u16 slot) - { - assert(slot < input_count); - return edges + slot; - } - - void add_output(Unit* unit, Function* function, Node* input) - { - unused(unit); - unused(function); - - if (input->output_count + input->input_count >= input->capacity) + if (input->output_count >= input->output_capacity) { trap(); } auto index = input->output_count; input->output_count += 1; - *input->get_output_slot(index) = this; + input->outputs[index] = { + .node = this, + .slot = slot, + }; } - void remove_output(Unit* unit, Function* function, u16 slot) + void remove_output(u16 slot) { - unused(unit); - unused(function); if (slot < output_count) { - Node** output_slot = get_output_slot(slot); - if (*output_slot) + Output* output_slot = &outputs[slot]; + if (output_slot->node) { trap(); } } } - void reallocate_edges(Unit* unit, u16 new_capacity) + u8 is_pinned() { - auto old_capacity = capacity; - assert(new_capacity > old_capacity); - auto length = output_count + input_count; - Node** new_edges = unit->arena->allocate_many(new_capacity); - memcpy(new_edges, edges, length * sizeof(Node*)); - memset(new_edges + length, 0, (new_capacity - length) * sizeof(Node)); - capacity = new_capacity; - edges = new_edges; - // TODO: free + u8 is_good_id = 0; + switch (id) + { + case Id::ROOT: + case Id::RETURN: + is_good_id = 1; + break; + case Id::PROJECTION: + case Id::CONSTANT_INT: + break; + } + return is_good_id | is_projection() | cfg_is_control_projection(); + } + + u8 is_projection() + { + switch (id) + { + case Id::PROJECTION: + return 1; + default: + return 0; + } + } + + u8 cfg_is_control_projection() + { + return is_projection() & (data_type.id == NodeDataType::Id::CONTROL); + } + + u8 is_cfg_control() + { + switch (data_type.id) + { + case NodeDataType::Id::CONTROL: + return 1; + case NodeDataType::Id::TUPLE: + for (Output& output : get_outputs()) + { + if (output.node->cfg_is_control_projection()) + { + return 1; + } + } + default: + return 0; + } + } +}; + +struct WorkList +{ + using BitsetBackingType = u32; + PinnedArray nodes; + PinnedArray bitset; + + global constexpr auto bit_count = sizeof(BitsetBackingType) * 8; + + void push(Node* node) + { + if (!test_and_set(node)) + { + nodes.append_one(node); + } + } + + u8 test_and_set(Node* node) + { + BitsetBackingType gvn_word = node->gvn / bit_count; + if (gvn_word >= bitset.capacity) + { + trap(); + } + BitsetBackingType gvn_mask = 1 << (node->gvn % bit_count); + if (bitset[gvn_word] & gvn_mask) + { + return 1; + } + else + { + bitset[gvn_word] |= gvn_mask; + return 0; + } + } + + void ensure_capacity(u32 capacity) + { + u32 aligned_capacity = align_forward(capacity, bit_count); + nodes.ensure_capacity(aligned_capacity); + auto bitset_length = aligned_capacity / bit_count; + unused(bitset.add(bitset_length)); + } + + void clear() + { + nodes.clear(); } }; @@ -1377,12 +1542,12 @@ fn u64 round_up_to_next_power_of_2(u64 n) return n; } -fn Hash intern_identifier(Unit* unit, String identifier) -{ - Hash hash = hash_bytes(identifier); - (void)unit->identifiers.get_or_put(hash, identifier); - return hash; -} +// fn Hash intern_identifier(Unit* unit, String identifier) +// { +// Hash hash = hash_bytes(identifier); +// (void)unit->identifiers.get_or_put(hash, identifier); +// return hash; +// } global String integer_names[] = { @@ -1522,9 +1687,9 @@ fn void unit_initialize(Unit* unit) SemaType* builtin_types = type_arena->allocate_many(builtin_type_count); *unit = { - .arena = Arena::init(Arena::default_size, Arena::minimum_granularity, KB(4)), - .node_arena = Arena::init(Arena::default_size, Arena::minimum_granularity, KB(64)), - .type_arena = type_arena, + // .arena = Arena::init(Arena::default_size, Arena::minimum_granularity, KB(4)), + // .node_arena = Arena::init(Arena::default_size, Arena::minimum_granularity, KB(64)), + // .type_arena = type_arena, .builtin_types = builtin_types, }; @@ -1533,21 +1698,21 @@ fn void unit_initialize(Unit* unit) .alignment = 1, .id = SemaTypeId::VOID, .resolved = 1, - .name = intern_identifier(unit, strlit("void")), + .name = strlit("void"), }; builtin_types[noreturn_type_index] = { .size = 0, .alignment = 1, .id = SemaTypeId::NORETURN, .resolved = 1, - .name = intern_identifier(unit, strlit("noreturn")), + .name = strlit("noreturn"), }; builtin_types[opaque_pointer_type_index] = { .size = 8, .alignment = 8, .id = SemaTypeId::POINTER, .resolved = 1, - .name = intern_identifier(unit, strlit("*any")), + .name = strlit("*any"), }; // TODO: float types @@ -1567,7 +1732,7 @@ fn void unit_initialize(Unit* unit) .id = SemaTypeId::INTEGER, .resolved = 1, .flags = static_cast(bit_count), - .name = intern_identifier(unit, integer_names[bit_count - 1]), + .name = integer_names[bit_count - 1], }; } @@ -1586,7 +1751,7 @@ fn void unit_initialize(Unit* unit) .id = SemaTypeId::INTEGER, .resolved = 1, .flags = static_cast(bit_count | (1 << (type_flags_bit_count - 1))), // Signedness bit - .name = intern_identifier(unit, integer_names[bit_count + 63]), + .name = integer_names[bit_count + 63], }; } } @@ -1608,6 +1773,16 @@ fn Unit* instance_add_unit(Instance* instance) return unit; } +// TODO: make it into an array +fn Thread* instance_add_thread(Instance* instance) +{ + auto* thread = instance->arena->allocate_one(); + *thread = { + .arena = Arena::init_default(KB(64)), + }; + return thread; +} + struct Parser { u64 i; @@ -1761,7 +1936,7 @@ fn void expect_character(Parser* parser, String src, u8 expected_ch) } } -fn String parse_identifier(Parser* parser, String src) +fn String parse_raw_identifier(Parser* parser, String src) { u64 identifier_start_index = parser->i; u64 is_string_literal = src.pointer[identifier_start_index] == '"'; @@ -1812,9 +1987,9 @@ typedef enum Keyword : u32 // return result; // } -fn Hash parse_and_intern_identifier(Parser* parser, Unit* unit, String src) +fn String parse_and_check_identifier(Parser* parser, String src) { - String identifier = parse_identifier(parser, src); + String identifier = parse_raw_identifier(parser, src); // Keyword keyword_index = parse_keyword(identifier); // if (expect(keyword_index != KEYWORD_INVALID, 0)) // { @@ -1823,11 +1998,10 @@ fn Hash parse_and_intern_identifier(Parser* parser, Unit* unit, String src) if (expect(identifier.equal(strlit("_")), 0)) { - return 0; + return {}; } - Hash result = intern_identifier(unit, identifier); - return result; + return identifier; } @@ -1841,19 +2015,19 @@ fn Hash parse_and_intern_identifier(Parser* parser, Unit* unit, String src) // return parser->i - parser->column + 1; // } -fn File* unit_add_file(Unit* unit, String file_path) +fn File* add_file(Arena* arena, String file_path) { - auto* file = unit->files.add_one(); + auto* file = arena->allocate_one(); *file = { .path = file_path, }; return file; } -fn void unit_file_read(Unit* unit, File* file) +fn void compiler_file_read(Arena* arena, File* file) { assert(file->status == FILE_STATUS_ADDED || file->status == FILE_STATUS_QUEUED); - file->source_code = file_read(unit->arena, file->path); + file->source_code = file_read(arena, file->path); file->status = FILE_STATUS_READ; } @@ -2080,9 +2254,35 @@ fn u64 parse_hex(String string) return value; } -[[nodiscard]] fn Node* parse_constant_integer(Parser* parser, Unit* unit, String src, SemaType* type) +struct ConstantIntData { + u64 value; + Node* input; + u32 gvn; + u8 bit_count; +}; + +[[nodiscard]] fn Node* add_constant_integer(Arena* arena, ConstantIntData data) +{ + auto* constant_int = Node::add(arena, { + .s = { + .type = { .id = NodeDataType::Id::INTEGER, .bit_count = data.bit_count, }, + .input_count = 1, + .id = Node::Id::CONSTANT_INT, + }, + .gvn = data.gvn, + .input_capacity = 1, + }); + constant_int->constant_int = data.value; + constant_int->set_input(data.input, 0); + return constant_int; +} + +[[nodiscard]] fn Node* parse_constant_integer(Parser* parser, Arena* arena, String src, SemaType* type, u32 gvn, Node* input) +{ + u64 value = 0; auto starting_ch = src[parser->i]; + if (starting_ch == '0') { auto follow_up_character = src[parser->i + 1]; @@ -2120,15 +2320,7 @@ fn u64 parse_hex(String string) } auto slice = src.slice(start, parser->i); - auto number = parse_hex(slice); - - auto* constant_int = Node::add(unit); - constant_int->id = Node::Id::CONSTANT_INT; - constant_int->data_type = { .id = NodeDataType::Id::INTEGER, .bit_count = type->get_bit_count() }; - constant_int->constant_int = number; - // TODO: is this fine? - constant_int->reallocate_edges(unit, 1); - return constant_int; + value = parse_hex(slice); } case IntegerPrefix::octal: trap(); @@ -2136,27 +2328,27 @@ fn u64 parse_hex(String string) trap(); } } else if (is_valid_after_zero) { + value = 0; parser->i += 1; - - auto* constant_int = Node::add(unit); - constant_int->id = Node::Id::CONSTANT_INT; - constant_int->data_type = { .id = NodeDataType::Id::INTEGER, .bit_count = type->get_bit_count() }; - constant_int->reallocate_edges(unit, 1); - constant_int->constant_int = 0; - return constant_int; } else { fail(); } - - trap(); } else { trap(); } + + Node* result = add_constant_integer(arena, { + .value = value, + .input = input, + .gvn = gvn, + .bit_count = type->get_bit_count(), + }); + return result; } -[[nodiscard]] fn Node* analyze_single_expression(Analyzer* analyzer, Parser* parser, Unit* unit, String src, SemaType* type, Side side) +[[nodiscard]] fn Node* analyze_single_expression(Analyzer* analyzer, Parser* parser, Unit* unit, Arena* arena, String src, SemaType* type, Side side) { unused(side); enum class Unary @@ -2166,6 +2358,7 @@ fn u64 parse_hex(String string) NEGATION, }; auto unary_operation = Unary::NONE; + auto* function = analyzer->function; auto original_starting_ch_index = parser->i; u8 original_starting_ch = src[original_starting_ch_index]; @@ -2225,9 +2418,9 @@ fn u64 parse_hex(String string) fail(); } - Node* constant_int = parse_constant_integer(parser, unit, src, integer_type); - constant_int->gvn = analyzer->function->node_count; - analyzer->function->node_count += 1; + auto gvn = function->node_count; + function->node_count += 1; + Node* constant_int = parse_constant_integer(parser, arena, src, integer_type, gvn, function->root_node); return constant_int; } @@ -2241,7 +2434,7 @@ fn u64 parse_hex(String string) } } -[[nodiscard]] fn Node* analyze_expression(Analyzer* analyzer, Parser* parser, Unit* unit, String src, SemaType* type, Side side) +[[nodiscard]] fn Node* analyze_expression(Analyzer* analyzer, Parser* parser, Unit* unit, Arena* arena, String src, SemaType* type, Side side) { enum class CurrentOperation { @@ -2269,7 +2462,7 @@ fn u64 parse_hex(String string) } else { - current_node = analyze_single_expression(analyzer, parser, unit, src, iteration_type, side); + current_node = analyze_single_expression(analyzer, parser, unit, arena, src, iteration_type, side); } skip_space(parser, src); @@ -2299,7 +2492,7 @@ fn u64 parse_hex(String string) } } -fn void analyze_local_block(Analyzer* analyzer, Parser* parser, Unit* unit, String src) +fn void analyze_local_block(Analyzer* analyzer, Parser* parser, Unit* unit, Arena* arena, String src) { expect_character(parser, src, block_start); while (1) @@ -2316,23 +2509,23 @@ fn void analyze_local_block(Analyzer* analyzer, Parser* parser, Unit* unit, Stri if (is_identifier_start(statement_start_ch)) { - String identifier = parse_identifier(parser, src); + String identifier = parse_raw_identifier(parser, src); if (identifier.equal(strlit("return"))) { skip_space(parser, src); - auto* return_value = analyze_expression(analyzer, parser, unit, src, analyzer->function->prototype.original_return_type, Side::right); + auto* return_value = analyze_expression(analyzer, parser, unit, arena, src, analyzer->function->prototype.original_return_type, Side::right); expect_character(parser, src, ';'); Function* function = analyzer->function; - Node* ret_node = Node::add_from_function(unit, function); - ret_node->id = Node::Id::RETURN; - ret_node->data_type = { .id = NodeDataType::Id::CONTROL }; - ret_node->reallocate_edges(unit, 4); - ret_node->input_count = 2; - ret_node->set_input(unit, function, function->root_node, 0); - ret_node->set_input(unit, function, return_value, 1); + Node* ret_node = Node::add_from_function(arena, function, { + .type = { .id = NodeDataType::Id::CONTROL }, + .input_count = 2, + .id = Node::Id::RETURN, + }); + ret_node->set_input(function->root_node, 0); + ret_node->set_input(return_value, 1); } else { @@ -2478,7 +2671,7 @@ fn SemaType* systemv_get_int_type_at_offset(SemaType* type, u64 offset, SemaType } } -fn void analyze_function(Parser* parser, Unit* unit, String src) +fn void analyze_function(Parser* parser, Thread* thread, Unit* unit, String src) { expect_character(parser, src, 'f'); expect_character(parser, src, 'n'); @@ -2503,7 +2696,7 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) break; } - String attribute_candidate = parse_identifier(parser, src); + String attribute_candidate = parse_raw_identifier(parser, src); u64 attribute_i; for (attribute_i = 0; attribute_i < array_length(function_attributes); attribute_i += 1) @@ -2527,7 +2720,7 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) expect_character(parser, src, '('); skip_space(parser, src); expect_character(parser, src, '.'); - String candidate_cc = parse_identifier(parser, src); + String candidate_cc = parse_raw_identifier(parser, src); skip_space(parser, src); expect_character(parser, src, ')'); @@ -2576,7 +2769,7 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) skip_space(parser, src); } - Hash name_hash = parse_and_intern_identifier(parser, unit, src); + String name = parse_and_check_identifier(parser, src); skip_space(parser, src); @@ -2597,7 +2790,7 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) break; } - String candidate_attribute = parse_identifier(parser, src); + String candidate_attribute = parse_raw_identifier(parser, src); skip_space(parser, src); switch (src.pointer[parser->i]) { @@ -2805,15 +2998,17 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) trap(); } - auto* function = unit->functions.add_one(); + // TODO: put them into an array? + auto* function = thread->arena->allocate_one(); + *function = { .symbol = { - .name = name_hash, + .name = name, .id = Symbol::Id::function, .linkage = symbol_attributes.external ? Symbol::Linkage::external : Symbol::Linkage::internal, }, .root_node = 0, - .parameters = unit->arena->allocate_many(argument_type_abis.length), + .parameters = thread->arena->allocate_many(argument_type_abis.length), .prototype = { .argument_type_abis = argument_type_abis.pointer, .original_argument_types = original_argument_types.pointer, @@ -2825,13 +3020,13 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) .node_count = 0, .parameter_count = (u16)argument_type_abis.length, }; + + function->root_node = Node::add_from_function_dynamic(thread->arena, function, { + .type = { .id = NodeDataType::Id::TUPLE }, + .input_count = 2, + .id = Node::Id::ROOT, + }, 4); - Node* root_node = Node::add_from_function(unit, function); - root_node->id = Node::Id::ROOT; - root_node->data_type = { - .id = NodeDataType::Id::TUPLE, - }; - root_node->reallocate_edges(unit, 4); // TODO: revisit // auto* control_node = root_node->project(unit, function, { @@ -2864,7 +3059,12 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) { Analyzer analyzer = {}; analyzer.function = function; - analyze_local_block(&analyzer, parser, unit, src); + analyze_local_block(&analyzer, parser, unit, thread->arena, src); + // TODO: remove hack + thread->functions = { + .pointer = function, + .length = 1, + }; } break; case 1: trap(); @@ -2879,9 +3079,9 @@ fn void analyze_function(Parser* parser, Unit* unit, String src) } } -fn void unit_file_analyze(Unit* unit, File* file) +fn void unit_file_analyze(Thread* thread, Unit* unit, File* file) { - unit_file_read(unit, file); + compiler_file_read(thread->arena, file); Parser parser = {}; String src = file->source_code; @@ -2908,7 +3108,7 @@ fn void unit_file_analyze(Unit* unit, File* file) case 'f': if (get_next_ch_safe(src, declaration_start_index) == 'n') { - analyze_function(&parser, unit, src); + analyze_function(&parser, thread, unit, src); } else { @@ -2923,11 +3123,117 @@ fn void unit_file_analyze(Unit* unit, File* file) global Instance instance; +// fn Node* instruction_selection(Node* node) +// { +// switch (node->id) +// { +// case Node::Id::PROJECTION: +// return node; +// case Node::Id::ROOT: +// { +// return node; +// } +// case Node::Id::RETURN: +// trap(); +// case Node::Id::CONSTANT_INT: +// trap(); +// break; +// } +// trap(); +// } + +// fn void function_codegen(Function* function) +// { +// WorkList helper = {}; +// helper.ensure_capacity(function->node_count); +// +// helper.push(function->root_node); +// PinnedArray pins = {}; +// +// u64 i = 0; +// while (i < helper.nodes.length) +// { +// Node* node = helper.nodes[i]; +// i += 1; +// +// if (node->is_pinned() & !node->is_projection()) +// { +// pins.append_one(node); +// } +// +// for (Output& output : node->get_outputs()) +// { +// helper.push(output.node); +// } +// } +// +// helper.clear(); +// +// WorkList walker = {}; +// walker.ensure_capacity(function->node_count); +// +// for (Node* pin_node : pins.slice()) +// { +// walker.push(pin_node); +// +// while (walker.nodes.length > 0) +// { +// Node* node = walker.nodes.pop(); +// +// if (!node->is_projection() & (node->output_count == 0)) +// { +// helper.push(node); +// continue; +// } +// +// if (node->data_type.id == NodeDataType::Id::MEMORY) +// { +// trap(); +// } +// +// Node* new_node = instruction_selection(node); +// if (new_node && new_node != node) +// { +// trap(); +// } +// +// u16 input_i = node->input_count; +// while (input_i > 0) +// { +// input_i -= 1; +// +// if (node->inputs[input_i]) +// { +// trap(); +// } +// } +// +// // TODO: region +// } +// } +// +// +// +// trap(); +// } + +String test_file_paths[] = { + strlit("tests/first/main.nat"), +}; + extern "C" void entry_point() { instance.arena = Arena::init(Arena::default_size, Arena::minimum_granularity, KB(4)); - Unit* unit = instance_add_unit(&instance); - File* file = unit_add_file(unit, strlit("tests/first/main.nat")); - unit_initialize(unit); - unit_file_analyze(unit, file); + + for (String test_file_path : test_file_paths) + { + print(test_file_path); + print(strlit("... ")); + Unit* unit = instance_add_unit(&instance); + unit_initialize(unit); + Thread* thread = instance_add_thread(&instance); + File* file = add_file(thread->arena, test_file_path); + unit_file_analyze(thread, unit, file); + print(strlit("[OK]\n")); + } } diff --git a/run.sh b/run.sh index 45adfce..adef565 100755 --- a/run.sh +++ b/run.sh @@ -1,10 +1,15 @@ #!/bin/sh +NEST_BUILD_DIR=build +NEST_EXE_NAME=nest set -ex -mkdir -p build +mkdir -p $NEST_BUILD_DIR time clang++ \ --o build/hatch \ +-o $NEST_BUILD_DIR/$NEST_EXE_NAME \ bootstrap/main.cpp \ bootstrap/entry.S \ +`# -Oz` \ +`# -march=native` \ +`# -Wl,-strip-all` \ -g \ -std=gnu++23 \ -Wall \ @@ -19,5 +24,5 @@ bootstrap/entry.S \ -fno-stack-protector \ -ferror-limit=1 \ `#-ftime-report` \ --MJ build/compile_commands.json -gf2 -ex r build/hatch +-MJ $NEST_BUILD_DIR/compile_commands.json +gf2 -ex r $NEST_BUILD_DIR/$NEST_EXE_NAME