aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-03-17 15:18:56 +0000
committergingerBill <bill@gingerbill.org>2022-03-17 15:18:56 +0000
commit714a5e8931c6113807077dd1653a94437b267708 (patch)
treec26c97ba868962fdb189e384d1448ff56ceb50e1
parent50503cb40530d81eb13056128a1419522d6a21ed (diff)
Begin work on the middle end system
-rw-r--r--src/checker_builtin_procs.hpp2
-rw-r--r--src/entity.cpp6
-rw-r--r--src/llvm_backend.cpp11
-rw-r--r--src/main.cpp16
-rw-r--r--src/middle_end.cpp632
-rw-r--r--src/middle_end.hpp370
6 files changed, 1025 insertions, 12 deletions
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index cba952ddf..ae8a38a0b 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -1,6 +1,6 @@
// checker_builtin_procs.hpp
-enum BuiltinProcId {
+enum BuiltinProcId : u16 {
BuiltinProc_Invalid,
BuiltinProc_len,
diff --git a/src/entity.cpp b/src/entity.cpp
index f5720293f..f88093f9d 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -2,6 +2,9 @@ struct Scope;
struct Checker;
struct Type;
struct DeclInfo;
+
+struct meProcedure;
+
struct lbModule;
struct lbProcedure;
@@ -173,6 +176,9 @@ struct Entity {
lbModule * code_gen_module;
lbProcedure *code_gen_procedure;
+ meProcedure *me_procedure;
+
+
u64 order_in_src;
String deprecated_message;
String warning_message;
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index f5cb84785..21e17eb5f 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -1,14 +1,3 @@
-#define MULTITHREAD_OBJECT_GENERATION 1
-
-#ifndef USE_SEPARATE_MODULES
-#define USE_SEPARATE_MODULES build_context.use_separate_modules
-#endif
-
-#ifndef MULTITHREAD_OBJECT_GENERATION
-#define MULTITHREAD_OBJECT_GENERATION 0
-#endif
-
-
#include "llvm_backend.hpp"
#include "llvm_abi.cpp"
#include "llvm_backend_opt.cpp"
diff --git a/src/main.cpp b/src/main.cpp
index 63b2c8386..d51557290 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -46,6 +46,17 @@ gb_global Timings global_timings = {0};
#include "checker.cpp"
#include "docs.cpp"
+#define MULTITHREAD_OBJECT_GENERATION 1
+
+#ifndef USE_SEPARATE_MODULES
+#define USE_SEPARATE_MODULES build_context.use_separate_modules
+#endif
+
+#ifndef MULTITHREAD_OBJECT_GENERATION
+#define MULTITHREAD_OBJECT_GENERATION 0
+#endif
+
+#include "middle_end.cpp"
#include "llvm_backend.cpp"
@@ -2732,6 +2743,11 @@ int main(int arg_count, char const **arg_ptr) {
return 0;
}
+ MAIN_TIME_SECTION("Middle End Pass");
+ if (!me_generate(checker)) {
+ return 1;
+ }
+
MAIN_TIME_SECTION("LLVM API Code Gen");
lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator);
if (!lb_init_generator(gen, checker)) {
diff --git a/src/middle_end.cpp b/src/middle_end.cpp
new file mode 100644
index 000000000..d93547ba4
--- /dev/null
+++ b/src/middle_end.cpp
@@ -0,0 +1,632 @@
+#include "middle_end.hpp"
+
+struct meGenerator {
+ CheckerInfo *info;
+
+ Array<String> output_object_paths;
+ Array<String> output_temp_paths;
+ String output_base;
+ String output_name;
+ PtrMap<AstPackage *, meModule *> modules;
+ meModule default_module;
+
+ PtrMap<Ast *, meProcedure *> anonymous_proc_lits;
+
+ std::atomic<u32> global_array_index;
+ std::atomic<u32> global_generated_index;
+};
+
+gb_internal meGenerator me_gen;
+
+gb_global Arena global_me_arena = {};
+gbAllocator me_allocator() {
+ return arena_allocator(&global_me_arena);
+}
+
+#define me_new(TYPE) gb_alloc_item(me_allocator(), TYPE)
+
+meValue me_value(meInstruction *instr) {
+ meValue value = {meValue_Instruction};
+ value.instr = instr;
+ return value;
+}
+meValue me_value(ExactValue *constant) {
+ meValue value = {meValue_ConstantValue};
+ value.constant = constant;
+ return value;
+}
+meValue me_value(meBlock *block) {
+ meValue value = {meValue_Block};
+ value.block = block;
+ return value;
+}
+meValue me_value(meProcedure *proc) {
+ meValue value = {meValue_Procedure};
+ value.proc = proc;
+ return value;
+}
+meValue me_value(meGlobalVariable *global) {
+ meValue value = {meValue_GlobalVariable};
+ value.global = global;
+ return value;
+}
+meValue me_value(meParameter *param) {
+ meValue value = {meValue_Parameter};
+ value.param = param;
+ return value;
+}
+
+meModule *me_pkg_module(AstPackage *pkg) {
+ if (pkg != nullptr) {
+ auto *found = map_get(&me_gen.modules, pkg);
+ if (found) {
+ return *found;
+ }
+ }
+ return &me_gen.default_module;
+}
+
+
+void me_add_entity(meModule *m, Entity *e, meValue val) {
+ if (e != nullptr) {
+ map_set(&m->values, e, val);
+ }
+}
+void me_add_member(meModule *m, String const &name, meValue val) {
+ if (name.len > 0) {
+ string_map_set(&m->members, name, val);
+ }
+}
+void me_add_member(meModule *m, StringHashKey const &key, meValue val) {
+ string_map_set(&m->members, key, val);
+}
+void me_add_procedure_value(meModule *m, meProcedure *p) {
+ if (p->entity != nullptr) {
+ map_set(&m->procedure_values, p, p->entity);
+ }
+ string_map_set(&m->procedures, p->name, p);
+}
+
+
+void me_add_foreign_library_path(meModule *m, Entity *e) {
+ if (e == nullptr) {
+ return;
+ }
+ GB_ASSERT(e->kind == Entity_LibraryName);
+ GB_ASSERT(e->flags & EntityFlag_Used);
+
+ for_array(i, e->LibraryName.paths) {
+ String library_path = e->LibraryName.paths[i];
+ if (library_path.len == 0) {
+ continue;
+ }
+
+ bool ok = true;
+ for_array(path_index, m->foreign_library_paths) {
+ String path = m->foreign_library_paths[path_index];
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (str_eq_ignore_case(path, library_path)) {
+ #else
+ if (str_eq(path, library_path)) {
+ #endif
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ array_add(&m->foreign_library_paths, library_path);
+ }
+ }
+}
+
+
+String me_mangle_name(meModule *m, Entity *e) {
+ String name = e->token.string;
+
+ AstPackage *pkg = e->pkg;
+ GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name));
+ String pkgn = pkg->name;
+ GB_ASSERT(!rune_is_digit(pkgn[0]));
+ if (pkgn == "llvm") {
+ pkgn = str_lit("llvm$");
+ }
+
+ isize max_len = pkgn.len + 1 + name.len + 1;
+ bool require_suffix_id = is_type_polymorphic(e->type, true);
+
+ if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) {
+ require_suffix_id = true;
+ } else if (is_blank_ident(e->token)) {
+ require_suffix_id = true;
+ }if (e->flags & EntityFlag_NotExported) {
+ require_suffix_id = true;
+ }
+
+ if (require_suffix_id) {
+ max_len += 21;
+ }
+
+ char *new_name = gb_alloc_array(permanent_allocator(), char, max_len);
+ isize new_name_len = gb_snprintf(
+ new_name, max_len,
+ "%.*s.%.*s", LIT(pkgn), LIT(name)
+ );
+ if (require_suffix_id) {
+ char *str = new_name + new_name_len-1;
+ isize len = max_len-new_name_len;
+ isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id);
+ new_name_len += extra-1;
+ }
+
+ String mangled_name = make_string((u8 const *)new_name, new_name_len-1);
+ return mangled_name;
+}
+
+String me_set_nested_type_name_ir_mangled_name(Entity *e, meProcedure *p) {
+ // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration
+ // and as a result, the declaration does not have time to determine what it should be
+
+ GB_ASSERT(e != nullptr && e->kind == Entity_TypeName);
+ if (e->TypeName.ir_mangled_name.len != 0) {
+ return e->TypeName.ir_mangled_name;
+ }
+ GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0);
+
+ if (p == nullptr) {
+ Entity *proc = nullptr;
+ if (e->parent_proc_decl != nullptr) {
+ proc = e->parent_proc_decl->entity;
+ } else {
+ Scope *scope = e->scope;
+ while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) {
+ scope = scope->parent;
+ }
+ GB_ASSERT(scope != nullptr);
+ GB_ASSERT(scope->flags & ScopeFlag_Proc);
+ proc = scope->procedure_entity;
+ }
+ GB_ASSERT(proc->kind == Entity_Procedure);
+ if (proc->me_procedure != nullptr) {
+ p = proc->me_procedure;
+ }
+ }
+
+ // NOTE(bill): Generate a new name
+ // parent_proc.name-guid
+ String ts_name = e->token.string;
+
+ if (p != nullptr) {
+ isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1;
+ char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
+ u32 guid = ++p->module->nested_type_name_guid;
+ name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%u", LIT(p->name), LIT(ts_name), guid);
+
+ String name = make_string(cast(u8 *)name_text, name_len-1);
+ e->TypeName.ir_mangled_name = name;
+ return name;
+ } else {
+ // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now
+ isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1;
+ char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
+ static u32 guid = 0;
+ guid += 1;
+ name_len = gb_snprintf(name_text, name_len, "_internal.%.*s-%u", LIT(ts_name), guid);
+
+ String name = make_string(cast(u8 *)name_text, name_len-1);
+ e->TypeName.ir_mangled_name = name;
+ return name;
+ }
+}
+
+
+String me_get_entity_name(meModule *m, Entity *e, String default_name) {
+ if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
+ return e->TypeName.ir_mangled_name;
+ }
+ GB_ASSERT(e != nullptr);
+
+ if (e->pkg == nullptr) {
+ return e->token.string;
+ }
+
+ if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) {
+ return me_set_nested_type_name_ir_mangled_name(e, nullptr);
+ }
+
+ String name = {};
+
+ bool no_name_mangle = false;
+
+ if (e->kind == Entity_Variable) {
+ bool is_foreign = e->Variable.is_foreign;
+ bool is_export = e->Variable.is_export;
+ no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export;
+ if (e->Variable.link_name.len > 0) {
+ return e->Variable.link_name;
+ }
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
+ return e->Procedure.link_name;
+ } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
+ no_name_mangle = true;
+ }
+
+ if (!no_name_mangle) {
+ name = me_mangle_name(m, e);
+ }
+ if (name.len == 0) {
+ name = e->token.string;
+ }
+
+ if (e->kind == Entity_TypeName) {
+ e->TypeName.ir_mangled_name = name;
+ } else if (e->kind == Entity_Procedure) {
+ e->Procedure.link_name = name;
+ }
+
+ return name;
+}
+
+
+
+void me_module_init(meModule *m, Checker *c) {
+ m->info = &c->info;
+
+ gbString module_name = gb_string_make(heap_allocator(), "odin_package");
+ if (m->pkg) {
+ module_name = gb_string_appendc(module_name, "-");
+ module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
+ } else if (USE_SEPARATE_MODULES) {
+ module_name = gb_string_appendc(module_name, "-builtin");
+ }
+
+ gbAllocator a = heap_allocator();
+ map_init(&m->values, a);
+ map_init(&m->soa_values, a);
+ string_map_init(&m->members, a);
+ map_init(&m->procedure_values, a);
+ string_map_init(&m->procedures, a);
+ string_map_init(&m->const_strings, a);
+ map_init(&m->equal_procs, a);
+ map_init(&m->hasher_procs, a);
+ array_init(&m->procedures_to_generate, a, 0, 1024);
+ array_init(&m->foreign_library_paths, a, 0, 1024);
+ array_init(&m->missing_procedures_to_check, a, 0, 16);
+
+ string_map_init(&m->objc_classes, a);
+ string_map_init(&m->objc_selectors, a);
+}
+
+
+bool me_generator_init(Checker *c) {
+ if (global_error_collector.count != 0) {
+ return false;
+ }
+
+ isize tc = c->parser->total_token_count;
+ if (tc < 2) {
+ return false;
+ }
+
+ meGenerator *gen = &me_gen;
+
+ String init_fullpath = c->parser->init_fullpath;
+
+ if (build_context.out_filepath.len == 0) {
+ gen->output_name = remove_directory_from_path(init_fullpath);
+ gen->output_name = remove_extension_from_path(gen->output_name);
+ gen->output_name = string_trim_whitespace(gen->output_name);
+ if (gen->output_name.len == 0) {
+ gen->output_name = c->info.init_scope->pkg->name;
+ }
+ gen->output_base = gen->output_name;
+ } else {
+ gen->output_name = build_context.out_filepath;
+ gen->output_name = string_trim_whitespace(gen->output_name);
+ if (gen->output_name.len == 0) {
+ gen->output_name = c->info.init_scope->pkg->name;
+ }
+ isize pos = string_extension_position(gen->output_name);
+ if (pos < 0) {
+ gen->output_base = gen->output_name;
+ } else {
+ gen->output_base = substring(gen->output_name, 0, pos);
+ }
+ }
+ gbAllocator ha = heap_allocator();
+ array_init(&gen->output_object_paths, ha);
+ array_init(&gen->output_temp_paths, ha);
+
+ gen->output_base = path_to_full_path(ha, gen->output_base);
+
+ gbString output_file_path = gb_string_make_length(ha, gen->output_base.text, gen->output_base.len);
+ output_file_path = gb_string_appendc(output_file_path, ".obj");
+ defer (gb_string_free(output_file_path));
+
+ gen->info = &c->info;
+
+ map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2);
+ map_init(&gen->anonymous_proc_lits, heap_allocator(), 1024);
+
+ if (USE_SEPARATE_MODULES) {
+ for_array(i, gen->info->packages.entries) {
+ AstPackage *pkg = gen->info->packages.entries[i].value;
+
+ auto m = gb_alloc_item(permanent_allocator(), meModule);
+ m->pkg = pkg;
+ map_set(&gen->modules, pkg, m);
+ me_module_init(m, c);
+ }
+ }
+
+ map_set(&gen->modules, cast(AstPackage *)nullptr, &gen->default_module);
+ me_module_init(&gen->default_module, c);
+ return true;
+}
+
+meProcedure *me_procedure_create(meModule *m, Entity *entity, bool ignore_body) {
+ GB_ASSERT(entity != nullptr);
+ GB_ASSERT(entity->kind == Entity_Procedure);
+ if (!entity->Procedure.is_foreign) {
+ GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type));
+ }
+
+ String link_name = {};
+
+ if (ignore_body) {
+ meModule *other_module = me_pkg_module(entity->pkg);
+ link_name = me_get_entity_name(other_module, entity);
+ } else {
+ link_name = me_get_entity_name(m, entity);
+ }
+
+ {
+ StringHashKey key = string_hash_string(link_name);
+ meValue *found = string_map_get(&m->members, key);
+ if (found) {
+ me_add_entity(m, entity, *found);
+ return string_map_must_get(&m->procedures, key);
+ }
+ }
+
+ meProcedure *p = me_new(meProcedure);
+
+ p->module = m;
+ entity->me_procedure = p;
+ p->entity = entity;
+ p->name = link_name;
+
+ DeclInfo *decl = entity->decl_info;
+
+ ast_node(pl, ProcLit, decl->proc_lit);
+ Type *pt = base_type(entity->type);
+ GB_ASSERT(pt->kind == Type_Proc);
+
+ p->type = entity->type;
+ p->type_expr = decl->type_expr;
+ p->body = pl->body;
+ switch (pl->inlining) {
+ case ProcInlining_none:
+ break;
+ case ProcInlining_inline:
+ p->flags |= meProcedureFlag_Inline;
+ break;
+ case ProcInlining_no_inline:
+ p->flags |= meProcedureFlag_NoInline;
+ break;
+ }
+ if (entity->Procedure.is_foreign) {
+ p->flags |= meProcedureFlag_Foreign;
+ }
+ if (entity->Procedure.is_export) {
+ p->flags |= meProcedureFlag_Export;
+ }
+ p->flags &= ~meProcedureFlag_EntryPoint;
+
+ gbAllocator a = heap_allocator();
+ p->children.allocator = a;
+ p->defer_stmts.allocator = a;
+ p->blocks.allocator = a;
+ p->branch_blocks.allocator = a;
+ p->context_stack.allocator = a;
+ p->scope_stack.allocator = a;
+
+ if (p->flags & meProcedureFlag_Foreign) {
+ me_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
+ }
+
+ if (entity->flags & EntityFlag_Cold) {
+ p->flags |= meProcedureFlag_Cold;
+ }
+
+ meValue proc_value = me_value(p);
+ me_add_entity(m, entity, proc_value);
+ me_add_member(m, p->name, proc_value);
+ me_add_procedure_value(m, p);
+
+ p->linkage = meLinkage_Strong; // default
+
+ if (p->flags & meProcedureFlag_Export) {
+ p->linkage = meLinkage_Export;
+ } else if (!(p->flags & meProcedureFlag_Foreign)) {
+ if (!USE_SEPARATE_MODULES) {
+ p->linkage = meLinkage_Internal;
+ // NOTE(bill): if a procedure is defined in package runtime and uses a custom link name,
+ // then it is very likely it is required by LLVM and thus cannot have internal linkage
+ if (entity->pkg != nullptr && entity->pkg->kind == Package_Runtime && p->body != nullptr) {
+ GB_ASSERT(entity->kind == Entity_Procedure);
+ String link_name = entity->Procedure.link_name;
+ if (entity->flags & EntityFlag_CustomLinkName &&
+ link_name != "") {
+ if (string_starts_with(link_name, str_lit("__"))) {
+ p->linkage = meLinkage_Strong;
+ } else {
+ p->linkage = meLinkage_Internal;
+ }
+ }
+ }
+ }
+ }
+ if (entity->flags & EntityFlag_CustomLinkage_Internal) {
+ p->linkage = meLinkage_Internal;
+ } else if (entity->flags & EntityFlag_CustomLinkage_Strong) {
+ p->linkage = meLinkage_Strong;
+ } else if (entity->flags & EntityFlag_CustomLinkage_Weak) {
+ p->linkage = meLinkage_Weak;
+ } else if (entity->flags & EntityFlag_CustomLinkage_LinkOnce) {
+ p->linkage = meLinkage_LinkOnce;
+ }
+
+ if (ignore_body) {
+ p->body = nullptr;
+ p->linkage = meLinkage_Strong;
+ }
+
+ return p;
+}
+
+meBlock *me_block_create(meProcedure *p, char const *name) {
+ auto *b = me_new(meBlock);
+ b->scope = p->curr_scope;
+ b->scope_index = p->scope_index;
+
+ b->preds.allocator = heap_allocator();
+ b->succs.allocator = heap_allocator();
+
+ array_add(&p->blocks, b);
+
+ return b;
+}
+
+void me_block_start(meProcedure *p, meBlock *b) {
+ p->curr_block = b;
+}
+
+void me_build_stmt(meProcedure *p, Ast *stmt) {
+
+}
+
+meContextData *me_push_context_onto_stack_from_implicit_parameter(meProcedure *p) {
+ // TODO(bill): me_push_context_onto_stack_from_implicit_parameter
+ return nullptr;
+}
+
+
+void me_procedure_body_begin(meProcedure *p) {
+ DeclInfo *decl = decl_info_of_entity(p->entity);
+ if (decl != nullptr) {
+ for_array(i, decl->labels) {
+ BlockLabel bl = decl->labels[i];
+ meBranchBlocks bb = {bl.label, nullptr, nullptr};
+ array_add(&p->branch_blocks, bb);
+ }
+ }
+
+ p->decl_block = me_block_create(p, "decls");
+ p->entry_block = me_block_create(p, "entry");
+ me_block_start(p, p->entry_block);
+
+ GB_ASSERT(p->type != nullptr);
+
+ {
+ // TODO(bill): parameter types
+ }
+ if (p->type->Proc.calling_convention == ProcCC_Odin) {
+ me_push_context_onto_stack_from_implicit_parameter(p);
+ }
+
+ me_block_start(p, p->entry_block);
+}
+
+void me_procedure_body_end(meProcedure *p) {
+ // TODO(bill): me_procedure_body_end
+}
+
+
+void me_generate_procedure(meModule *m, meProcedure *p) {
+ if (p->is_done) {
+ return;
+ }
+ if (p->body != nullptr) {
+ m->curr_procedure = p;
+ me_procedure_body_begin(p);
+ me_build_stmt(p, p->body);
+ me_procedure_body_end(p);
+ p->is_done = true;
+ m->curr_procedure = nullptr;
+ }
+
+ gb_printf_err("[procedure] %.*s\n", LIT(p->name));
+
+ // Add Flags
+ if (p->body != nullptr) {
+ if (p->name == "memcpy" || p->name == "memmove" ||
+ p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
+ string_starts_with(p->name, str_lit("llvm.memcpy")) ||
+ string_starts_with(p->name, str_lit("llvm.memmove"))) {
+ p->flags |= meProcedureFlag_WithoutMemcpy;
+ }
+ }
+}
+
+
+
+bool me_generate(Checker *c) {
+ if (!me_generator_init(c)) {
+ return false;
+ }
+ CheckerInfo *info = &c->info;
+ auto *min_dep_set = &info->minimum_dependency_set;
+
+
+ for_array(i, info->entities) {
+ Entity *e = info->entities[i];
+ String name = e->token.string;
+ Scope * scope = e->scope;
+
+ if ((scope->flags & ScopeFlag_File) == 0) {
+ continue;
+ }
+
+ Scope *package_scope = scope->parent;
+ GB_ASSERT(package_scope->flags & ScopeFlag_Pkg);
+
+ switch (e->kind) {
+ case Entity_Variable:
+ // NOTE(bill): Handled above as it requires a specific load order
+ continue;
+ case Entity_ProcGroup:
+ case Entity_TypeName:
+ continue;
+
+ case Entity_Procedure:
+ break;
+ }
+
+ if (!ptr_set_exists(min_dep_set, e)) {
+ // NOTE(bill): Nothing depends upon it so doesn't need to be built
+ continue;
+ }
+
+ meModule *m = me_pkg_module(e->pkg);
+ String mangled_name = me_get_entity_name(m, e);
+
+ switch (e->kind) {
+ case Entity_Procedure:
+ array_add(&m->procedures_to_generate, me_procedure_create(m, e));
+ break;
+ }
+ }
+
+ for_array(j, me_gen.modules.entries) {
+ meModule *m = me_gen.modules.entries[j].value;
+ for_array(i, m->procedures_to_generate) {
+ meProcedure *p = m->procedures_to_generate[i];
+ me_generate_procedure(m, p);
+ }
+ }
+
+ gb_printf_err("[middle end pass done]\n");
+ gb_exit(0);
+ return true;
+} \ No newline at end of file
diff --git a/src/middle_end.hpp b/src/middle_end.hpp
new file mode 100644
index 000000000..f8e01cbd9
--- /dev/null
+++ b/src/middle_end.hpp
@@ -0,0 +1,370 @@
+/*
+ Odin Middle End Notation
+
+ "me" prefix means middle end
+*/
+
+struct meModule; // Build/Translation Unit
+struct meValue;
+struct meProcedure;
+struct meBlock;
+struct meInstruction;
+struct meGlobalVariable;
+
+enum meOpKind : u8 {
+ meOp_Invalid = 0,
+
+ meOp_Unreachable,
+ meOp_Return,
+ meOp_Jump,
+ meOp_CondJump,
+ meOp_Switch,
+ meOp_Phi,
+
+ // Unary Operators
+ meOp_FNeg,
+
+ // Binary Arithmetic Operators
+ meOp_Add,
+ meOp_Sub,
+ meOp_Mul,
+ meOp_Div,
+ meOp_Rem,
+
+ // Binary Bitwise Operators
+ meOp_Shl,
+ meOp_LShr,
+ meOp_AShr,
+ meOp_And,
+ meOp_Or,
+ meOp_Xor,
+
+ // Memory Operators
+ meOp_Alloca,
+ meOp_Load,
+ meOp_Store,
+ meOp_GetElementPtr,
+
+ // Cast Operators
+ meOp_Cast,
+ meOp_Transmute,
+
+ // Binary Comparison Operators
+ meOp_Eq,
+ meOp_NotEq,
+ meOp_Lt,
+ meOp_LtEq,
+ meOp_Gt,
+ meOp_GtEq,
+ meOp_Min,
+ meOp_Max,
+
+ // Ternary Operators
+ meOp_Select,
+
+ // Other
+ meOp_Call,
+ meOp_BuiltinCall,
+
+ meOp_ExtractValue,
+ meOp_Swizzle,
+
+ // Atomics
+ meOp_Fence,
+ meOp_AtomicCmpXchg,
+};
+
+enum meInstructionFlags : u16 {
+ meInstructionFlag_Volatile = 1<<0,
+ meInstructionFlag_AtomicRMW = 1<<1,
+ meInstructionFlag_ForceInline = 1<<2,
+ meInstructionFlag_ForceNoInline = 1<<3,
+};
+
+enum meAtomicOrderingKind : u8 {
+ meAtomicOrdering_NotAtomic,
+ meAtomicOrdering_Unordered,
+ meAtomicOrdering_Monotonic,
+ meAtomicOrdering_Acquire,
+ meAtomicOrdering_Release,
+ meAtomicOrdering_AcquireRelease,
+ meAtomicOrdering_SequentiallyConsistent,
+ meAtomicOrdering_COUNT,
+};
+
+enum meLinkageKind : u8 {
+ meLinkage_Strong,
+ meLinkage_Weak,
+ meLinkage_Internal,
+ meLinkage_LinkOnce,
+ meLinkage_Export,
+};
+
+
+enum {me_INSTRUCTION_MAX_ARG_COUNT = 4};
+
+struct meInstruction {
+ meOpKind op;
+ meAtomicOrderingKind atomic_ordering;
+ u16 flags;
+ u16 alignment;
+ u16 uses;
+
+ Type * type;
+ meProcedure *parent;
+ TokenPos pos;
+
+ meValue *operands[me_INSTRUCTION_MAX_ARG_COUNT];
+ isize operand_count;
+
+ Slice<meValue> *extra_operands; // non-null if used
+};
+
+struct meBlock {
+ meProcedure * parent;
+ String name;
+ Array<meInstruction *> instructions;
+ Scope * scope;
+ i32 scope_index;
+ Array<meBlock *> preds;
+ Array<meBlock *> succs;
+};
+
+struct meBranchBlocks {
+ Ast *label;
+ meBlock *break_;
+ meBlock *continue_;
+};
+
+struct meTargetList {
+ meTargetList *prev;
+ bool is_block;
+ meBlock *break_;
+ meBlock *continue_;
+ meBlock *fallthrough_;
+};
+
+enum meGlobalVariableFlags : u16 {
+ meGlobalVariableFlag_ThreadLocal_default = 1<<0,
+ meGlobalVariableFlag_ThreadLocal_localdynamic = 1<<1,
+ meGlobalVariableFlag_ThreadLocal_initialexec = 1<<2,
+ meGlobalVariableFlag_ThreadLocal_localexec = 1<<3,
+};
+
+
+struct meGlobalVariable {
+ meModule * module;
+ Entity * entity;
+ Type * type;
+ String name; // link name
+ meLinkageKind linkage;
+ u16 flags;
+ ExactValue value;
+ i32 uses;
+ DeclInfo * decl;
+};
+
+struct meParameter {
+ String name;
+ Entity * entity;
+ meProcedure *parent;
+ i32 uses;
+};
+
+
+enum meValueKind : u8 {
+ meValue_Invalid = 0,
+ meValue_Instruction,
+ meValue_ConstantValue,
+ meValue_Block,
+ meValue_Procedure,
+ meValue_GlobalVariable,
+ meValue_Parameter,
+};
+struct meValue {
+ meValueKind kind;
+ union {
+ meInstruction *instr;
+ ExactValue *constant;
+ meBlock *block;
+ meProcedure *proc;
+ meGlobalVariable *global;
+ meParameter *param;
+ };
+};
+
+enum meAddrKind : u32 {
+ meAddr_Default = 0,
+ meAddr_Map,
+ meAddr_Context,
+ meAddr_SoaVariable,
+
+ meAddr_RelativePointer,
+ meAddr_RelativeSlice,
+
+ meAddr_Swizzle,
+ meAddr_SwizzleLarge,
+};
+
+struct meAddr {
+ meAddrKind kind;
+ meValue addr;
+ union {
+ struct {
+ meValue key;
+ Type *type;
+ Type *result;
+ } map;
+ struct {
+ Selection sel;
+ } ctx;
+ struct {
+ meValue index;
+ Ast *index_expr;
+ } soa;
+ struct {
+ meValue index;
+ Ast *node;
+ } index_set;
+ struct {
+ bool deref;
+ } relative;
+ struct {
+ Type *type;
+ u8 count; // 2, 3, or 4 components
+ u8 indices[4];
+ } swizzle;
+ struct {
+ Type *type;
+ Slice<i32> indices;
+ } swizzle_large;
+ };
+};
+
+
+
+struct meContextData {
+ meAddr ctx;
+ i32 scope_index;
+ i32 uses;
+};
+
+enum meDeferKind {
+ meDefer_Node,
+ meDefer_Proc,
+};
+
+struct meDefer {
+ meDeferKind kind;
+ i32 scope_index;
+ i32 context_stack_count;
+ meBlock * block;
+ union {
+ Ast *stmt;
+ struct {
+ meValue deferred;
+ Array<meValue> result_as_args;
+ } proc;
+ };
+};
+
+
+enum meProcedureFlags : u32 {
+ meProcedureFlag_Foreign = 1<<1,
+ meProcedureFlag_Export = 1<<2,
+ meProcedureFlag_EntryPoint = 1<<3,
+ meProcedureFlag_Startup = 1<<4,
+
+ meProcedureFlag_Inline = 1<<5,
+ meProcedureFlag_NoInline = 1<<6,
+
+ meProcedureFlag_Cold = 1<<7,
+ meProcedureFlag_Hot = 1<<8,
+ meProcedureFlag_WithoutMemcpy = 1<<9,
+};
+
+struct meProcedure {
+ meModule * module;
+ Entity * entity;
+ Type * type;
+ String name; // link name
+ meLinkageKind linkage;
+ u32 flags;
+ i32 uses;
+ BuiltinProcId builtin_id;
+
+ u16 state_flags;
+ bool is_done;
+
+ meProcedure * parent;
+ Array<meProcedure *> children;
+
+ Ast *type_expr;
+ Ast *body;
+ u64 tags;
+
+ meAddr return_ptr;
+ Array<meDefer> defer_stmts;
+
+ Array<meBlock *> blocks;
+ meBlock * decl_block;
+ meBlock * entry_block;
+ meBlock * curr_block;
+
+ Array<meBranchBlocks> branch_blocks;
+
+ Scope *curr_scope;
+ i32 scope_index;
+
+ meTargetList *target_list;
+
+ Ast *curr_stmt;
+
+ Array<Scope *> scope_stack;
+
+ Array<meContextData> context_stack;
+};
+
+struct meModule { // Build/Translation Unit
+ CheckerInfo *info;
+ AstPackage *pkg; // associated
+
+ PtrMap<Entity *, meValue> values;
+ PtrMap<Entity *, meAddr> soa_values;
+ StringMap<meValue> members;
+ StringMap<meProcedure *> procedures;
+ PtrMap<meProcedure *, Entity *> procedure_values;
+ Array<meProcedure *> missing_procedures_to_check;
+
+ StringMap<meValue> const_strings;
+
+ PtrMap<Type *, meProcedure *> equal_procs;
+ PtrMap<Type *, meProcedure *> hasher_procs;
+
+ u32 nested_type_name_guid;
+
+ Array<meProcedure *> procedures_to_generate;
+ Array<String> foreign_library_paths;
+
+ meProcedure *curr_procedure;
+
+ StringMap<meAddr> objc_classes;
+ StringMap<meAddr> objc_selectors;
+};
+
+
+bool me_generate(Checker *c);
+
+String me_get_entity_name(meModule *m, Entity *e, String default_name = {});
+
+meProcedure *me_procedure_create(meModule *m, Entity *entity, bool ignore_body=false);
+
+
+
+
+meValue me_value(meInstruction *instr);
+meValue me_value(ExactValue *constant);
+meValue me_value(meBlock *block);
+meValue me_value(meProcedure *proc);
+meValue me_value(meGlobalVariable *global);
+meValue me_value(meParameter *param);