From 16bd6c7205a1eea264cc2daa077f4c7f096868af Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 19 Mar 2022 13:03:08 +0000 Subject: [PATCH] Mock out instructions emit calls --- src/check_expr.cpp | 9 + src/llvm_backend_expr.cpp | 3 - src/middle_end.cpp | 297 +----------- src/middle_end.hpp | 95 ++-- src/middle_end_core.cpp | 925 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 993 insertions(+), 336 deletions(-) create mode 100644 src/middle_end_core.cpp diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 577f3b07c..937995df3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -119,6 +119,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y); void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); @@ -850,6 +851,14 @@ bool internal_check_is_assignable_to(Type *src, Type *dst) { return check_is_assignable_to(nullptr, &x, dst); } +bool internal_check_is_castable_to(Type *src, Type *dst) { + Operand x = {}; + x.type = src; + x.mode = Addressing_Value; + return check_is_castable_to(nullptr, &x, dst); +} + + AstPackage *get_package_of_type(Type *type) { for (;;) { if (type == nullptr) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4294747b9..4643b5322 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2182,9 +2182,6 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } else { Type *lt = left.type; Type *rt = right.type; - - lt = left.type; - rt = right.type; i64 ls = type_size_of(lt); i64 rs = type_size_of(rt); diff --git a/src/middle_end.cpp b/src/middle_end.cpp index d93547ba4..42b96a1b3 100644 --- a/src/middle_end.cpp +++ b/src/middle_end.cpp @@ -1,272 +1,5 @@ #include "middle_end.hpp" - -struct meGenerator { - CheckerInfo *info; - - Array output_object_paths; - Array output_temp_paths; - String output_base; - String output_name; - PtrMap modules; - meModule default_module; - - PtrMap anonymous_proc_lits; - - std::atomic global_array_index; - std::atomic 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; -} - +#include "middle_end_core.cpp" void me_module_init(meModule *m, Checker *c) { @@ -402,7 +135,7 @@ meProcedure *me_procedure_create(meModule *m, Entity *entity, bool ignore_body) Type *pt = base_type(entity->type); GB_ASSERT(pt->kind == Type_Proc); - p->type = entity->type; + p->type = base_type(entity->type); p->type_expr = decl->type_expr; p->body = pl->body; switch (pl->inlining) { @@ -485,32 +218,6 @@ meProcedure *me_procedure_create(meModule *m, Entity *entity, bool ignore_body) 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); diff --git a/src/middle_end.hpp b/src/middle_end.hpp index f8e01cbd9..cf9a7e5cf 100644 --- a/src/middle_end.hpp +++ b/src/middle_end.hpp @@ -9,7 +9,31 @@ struct meValue; struct meProcedure; struct meBlock; struct meInstruction; +struct meConstant; struct meGlobalVariable; +struct meParameter; + + +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; + meConstant *constant; + meBlock *block; + meProcedure *proc; + meGlobalVariable *global; + meParameter *param; + }; +}; enum meOpKind : u8 { meOp_Invalid = 0, @@ -22,7 +46,9 @@ enum meOpKind : u8 { meOp_Phi, // Unary Operators - meOp_FNeg, + meOp_Neg, + meOp_LogicalNot, + meOp_BitwiseNot, // Binary Arithmetic Operators meOp_Add, @@ -43,7 +69,11 @@ enum meOpKind : u8 { meOp_Alloca, meOp_Load, meOp_Store, + meOp_UnalignedLoad, + meOp_UnalignedStore, meOp_GetElementPtr, + meOp_PtrOffset, + meOp_PtrSub, // Cast Operators meOp_Cast, @@ -56,6 +86,7 @@ enum meOpKind : u8 { meOp_LtEq, meOp_Gt, meOp_GtEq, + meOp_Min, meOp_Max, @@ -69,16 +100,20 @@ enum meOpKind : u8 { meOp_ExtractValue, meOp_Swizzle, + meOp_Alias, // alias of another value + // Atomics meOp_Fence, + meOp_AtomicXchg, meOp_AtomicCmpXchg, }; enum meInstructionFlags : u16 { - meInstructionFlag_Volatile = 1<<0, - meInstructionFlag_AtomicRMW = 1<<1, - meInstructionFlag_ForceInline = 1<<2, - meInstructionFlag_ForceNoInline = 1<<3, + meInstructionFlag_Volatile = 1<<0, + meInstructionFlag_AtomicRMW = 1<<1, + meInstructionFlag_ForceInline = 1<<2, + meInstructionFlag_ForceNoInline = 1<<3, + meInstructionFlag_HasSideEffects = 1<<4, }; enum meAtomicOrderingKind : u8 { @@ -110,14 +145,19 @@ struct meInstruction { u16 alignment; u16 uses; - Type * type; + Type * type; meProcedure *parent; - TokenPos pos; + TokenPos pos; - meValue *operands[me_INSTRUCTION_MAX_ARG_COUNT]; - isize operand_count; + meValue ops[me_INSTRUCTION_MAX_ARG_COUNT]; + isize op_count; - Slice *extra_operands; // non-null if used + Slice *extra_ops; // non-null if used +}; + +struct meConstant { + ExactValue value; + Type *type; }; struct meBlock { @@ -165,32 +205,10 @@ struct meGlobalVariable { }; struct meParameter { - String name; - Entity * entity; + 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; - }; + i32 uses; }; enum meAddrKind : u32 { @@ -360,11 +378,12 @@ 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(meConstant *constant); meValue me_value(meBlock *block); meValue me_value(meProcedure *proc); meValue me_value(meGlobalVariable *global); meValue me_value(meParameter *param); + + +meValue me_emit_conv(meProcedure *p, meValue value, Type *type); diff --git a/src/middle_end_core.cpp b/src/middle_end_core.cpp new file mode 100644 index 000000000..4b19b5e55 --- /dev/null +++ b/src/middle_end_core.cpp @@ -0,0 +1,925 @@ + +struct meGenerator { + CheckerInfo *info; + + Array output_object_paths; + Array output_temp_paths; + String output_base; + String output_name; + PtrMap modules; + meModule default_module; + + PtrMap anonymous_proc_lits; + + std::atomic global_array_index; + std::atomic 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(meConstant *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; +} + +bool me_is_const(meValue value) { + return value.kind == meValue_ConstantValue; +} + +bool me_is_const_nil(meValue value) { + if (value.kind == meValue_ConstantValue) { + return value.constant->value.kind == ExactValue_Invalid; + } + return false; +} + + +meValue me_use(meValue const &value) { + switch (value.kind) { + case meValue_Instruction: value.instr->uses += 1; break; + case meValue_Procedure: value.proc->uses += 1; break; + case meValue_GlobalVariable: value.global->uses += 1; break; + case meValue_Parameter: value.param->uses += 1; break; + } + return value; +} + +i32 me_uses(meValue const &value) { + switch (value.kind) { + case meValue_Instruction: return value.instr->uses; + case meValue_Procedure: return value.proc->uses; + case meValue_GlobalVariable: return value.global->uses; + case meValue_Parameter: return value.param->uses; + } + GB_PANIC("invalid value to call on uses"); + return 0; +} + +void me_remove_use(meValue const &value) { + switch (value.kind) { + case meValue_Instruction: GB_ASSERT(value.instr->uses > 0); value.instr->uses -= 1; break; + case meValue_Procedure: GB_ASSERT(value.proc->uses > 0); value.proc->uses -= 1; break; + case meValue_GlobalVariable: GB_ASSERT(value.global->uses > 0); value.global->uses -= 1; break; + case meValue_Parameter: GB_ASSERT(value.param->uses > 0); value.param->uses -= 1; break; + } +} + + +meAddr me_addr(meValue value) { + meAddr addr = {}; + addr.kind = meAddr_Default; + addr.addr = value; + return addr; +} + +Type *me_type(meValue value) { + switch (value.kind) { + case meValue_Invalid: + return nullptr; + case meValue_Instruction: + return value.instr->type; + case meValue_ConstantValue: + return value.constant->type; + case meValue_Block: + return nullptr; + case meValue_Procedure: + return value.proc->type; + case meValue_GlobalVariable: + return value.global->type; + case meValue_Parameter: + return value.param->entity->type; + } + return nullptr; +} + +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; +} + +meInstruction *me_last_instruction(meBlock *block) { + if (block && block->instructions.count > 0) { + return block->instructions[block->instructions.count-1]; + } + return nullptr; +} + +bool me_is_instruction_terminator(meOpKind op) { + switch (op) { + case meOp_Unreachable: + case meOp_Return: + case meOp_Jump: + case meOp_CondJump: + case meOp_Switch: + return true; + } + return false; +} + + +bool me_is_last_instruction_terminator(meBlock *b) { + meInstruction *instr = me_last_instruction(b); + return instr != nullptr && me_is_instruction_terminator(instr->op); +} + +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_add_edge(meBlock *from, meBlock *to) { + if (!me_is_last_instruction_terminator(from)) { + array_add(&from->succs, to); + array_add(&to->preds, from); + } +} + + +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; +} + + + +meInstruction *me_create_instruction(meProcedure *p, meOpKind op) { + meInstruction *instr = me_new(meInstruction); + instr->op = op; + + GB_ASSERT(p->curr_block != nullptr); + + if (!me_is_last_instruction_terminator(p->curr_block)) { + if (instr->parent != nullptr) { + GB_ASSERT(instr->parent == p); + } else { + instr->parent = p; + } + array_add(&p->curr_block->instructions, instr); + } + + return instr; +} + +void me_emit_unreachable(meProcedure *p) { + me_create_instruction(p, meOp_Unreachable); +} + +void me_emit_return_empty(meProcedure *p) { + GB_ASSERT(p->type->Proc.result_count == 0); + + me_create_instruction(p, meOp_Return); +} +void me_emit_return(meProcedure *p, meValue value) { + auto *instr = me_create_instruction(p, meOp_Return); + if (value.kind != meValue_Invalid) { + instr->ops[0] = me_use(value); + instr->op_count = 1; + } +} + +void me_emit_jump(meProcedure *p, meBlock *block) { + auto *jump = me_create_instruction(p, meOp_Jump); + jump->ops[0] = me_use(me_value(block)); + jump->op_count = 1; + + me_block_add_edge(p->curr_block, block); +} + +void me_emit_cond_jump(meProcedure *p, meValue cond, meBlock *true_block, meBlock *false_block) { + if (p->curr_block == nullptr) { + return; + } + + if (cond.kind == meValue_ConstantValue) { + GB_ASSERT(cond.constant->value.kind == ExactValue_Bool); + if (cond.constant->value.value_bool) { + me_emit_jump(p, true_block); + } else { + me_emit_jump(p, false_block); + } + return; + } + + auto *jump = me_create_instruction(p, meOp_CondJump); + jump->ops[0] = me_use(cond); + jump->ops[1] = me_use(me_value(true_block)); + jump->ops[2] = me_use(me_value(false_block)); + jump->op_count = 3; + + me_block_add_edge(p->curr_block, true_block); + me_block_add_edge(p->curr_block, false_block); +} + + +meValue me_emit_neg(meProcedure *p, meValue value) { + Type *type = me_type(value); + GB_ASSERT(type != nullptr); + type = base_type(core_array_type(type)); + GB_ASSERT(is_type_numeric(type)); + + auto *n = me_create_instruction(p, meOp_Neg); + n->type = me_type(value); + n->ops[0] = me_use(value); + n->op_count = 1; + + return me_value(n); +} + +meValue me_emit_logical_not(meProcedure *p, meValue value) { + Type *type = me_type(value); + GB_ASSERT(type != nullptr); + type = base_type(core_array_type(type)); + GB_ASSERT(is_type_boolean(type)); + + auto *n = me_create_instruction(p, meOp_LogicalNot); + n->type = me_type(value); + n->ops[0] = me_use(value); + n->op_count = 1; + + return me_value(n); +} + +meValue me_emit_bitwise_not(meProcedure *p, meValue value) { + Type *type = me_type(value); + GB_ASSERT(type != nullptr); + type = base_type(core_array_type(type)); + GB_ASSERT(is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type)); + + auto *n = me_create_instruction(p, meOp_BitwiseNot); + n->type = me_type(value); + n->ops[0] = me_use(value); + n->op_count = 1; + + return me_value(n); +} + + +meValue me_emit_binary_op(meProcedure *p, meOpKind op, meValue left, meValue right, Type *type) { + GB_ASSERT(type != nullptr); + + switch (op) { + case meOp_Add: + case meOp_Sub: + case meOp_Mul: + case meOp_Div: + case meOp_Rem: + case meOp_Shl: + case meOp_LShr: + case meOp_AShr: + case meOp_And: + case meOp_Or: + case meOp_Xor: + case meOp_Eq: + case meOp_NotEq: + case meOp_Lt: + case meOp_LtEq: + case meOp_Gt: + case meOp_GtEq: + case meOp_Min: + case meOp_Max: + break; + default: + GB_PANIC("Unsupported binary op"); + } + + auto *b = me_create_instruction(p, op); + b->type = type; + b->ops[0] = me_use(left); + b->ops[1] = me_use(right); + b->op_count = 2; + + return me_value(b); +} + + +meAddr me_add_local(meProcedure *p, Type *type, Entity *e, bool zero_init) { + meInstruction *var = nullptr; + meBlock *curr_block = p->curr_block; + p->curr_block = p->decl_block; + var = me_create_instruction(p, meOp_Alloca); + p->curr_block = curr_block; + + var->type = alloc_type_pointer(type); + + u16 alignment = cast(u16)type_align_of(type); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + var->alignment = alignment; + + // TODO(bill): ZERO me_add_local + + return me_addr(me_value(var)); +} + + +meValue me_emit_inline_alloca(meProcedure *p, Type *type, u16 alignment) { + meInstruction *var = me_create_instruction(p, meOp_Alloca); + var->type = alloc_type_pointer(type); + var->alignment = alignment; + return me_value(var); +} + +meValue me_emit_load_with_alignment_hint(meProcedure *p, meValue const &value, u16 alignment) { + GB_ASSERT(alignment == 0 || gb_is_power_of_two(alignment)); + Type *type = me_type(value); + GB_ASSERT(type != nullptr); + GB_ASSERT(is_type_pointer(type)); + + meInstruction *v = me_create_instruction(p, meOp_Load); + v->type = type; + v->ops[0] = me_use(value); + v->op_count = 1; + v->alignment = alignment; + + return me_value(v); +} + +meValue me_emit_load(meProcedure *p, meValue const &value) { + return me_emit_load_with_alignment_hint(p, value, 0); +} + +meValue me_emit_unaligned_load_with_alignment_hint(meProcedure *p, meValue const &value, u16 alignment) { + GB_ASSERT(alignment == 0 || gb_is_power_of_two(alignment)); + Type *type = me_type(value); + GB_ASSERT(type != nullptr); + GB_ASSERT(is_type_pointer(type)); + + meInstruction *v = me_create_instruction(p, meOp_UnalignedLoad); + v->type = type; + v->ops[0] = me_use(value); + v->op_count = 1; + v->alignment = alignment; + + return me_value(v); +} + +meValue me_emit_unaligned_load(meProcedure *p, meValue const &value) { + return me_emit_unaligned_load_with_alignment_hint(p, value, 0); +} + +void me_emit_store(meProcedure *p, meValue dst, meValue src) { + Type *dst_type = me_type(dst); + GB_ASSERT(is_type_pointer(dst_type)); + src = me_emit_conv(p, src, type_deref(dst_type)); + + meInstruction *v = me_create_instruction(p, meOp_Store); + v->ops[0] = me_use(dst); + v->ops[1] = me_use(src); + v->op_count = 2; +} + +void me_emit_unaligned_store(meProcedure *p, meValue dst, meValue src) { + Type *dst_type = me_type(dst); + GB_ASSERT(is_type_pointer(dst_type)); + src = me_emit_conv(p, src, type_deref(dst_type)); + + meInstruction *v = me_create_instruction(p, meOp_UnalignedStore); + v->ops[0] = me_use(dst); + v->ops[1] = me_use(src); + v->op_count = 2; +} + + +meValue me_const_int(i64 value, Type *type) { + meConstant *constant = me_new(meConstant); + constant->value = exact_value_i64(value); + constant->type = type; + return me_value(constant); +} + +meValue me_emit_gep(meProcedure *p, meValue value, isize index) { + Type *ptr_type = me_type(value); + GB_ASSERT(is_type_pointer(ptr_type)); + Type *t = base_type(type_deref(ptr_type)); + gb_unused(t); + GB_ASSERT(index >= 0); + + Type *type = nullptr; // TODO(bill): type determination + meInstruction *v = me_create_instruction(p, meOp_GetElementPtr); + v->type = type; + v->ops[0] = me_use(value); + v->ops[1] = me_use(me_const_int(cast(i64)index, t_int)); + v->op_count = 2; + + return me_value(v); +} + +meValue me_emit_ev(meProcedure *p, meValue value, isize index) { + Type *value_type = me_type(value); + GB_ASSERT(!is_type_pointer(value_type)); + Type *t = base_type(value_type); + gb_unused(t); + GB_ASSERT(index >= 0); + + Type *type = nullptr; // TODO(bill): type determination + meInstruction *v = me_create_instruction(p, meOp_ExtractValue); + v->type = type; + v->ops[0] = me_use(value); + v->ops[1] = me_use(me_const_int(cast(i64)index, t_int)); + v->op_count = 2; + + return me_value(v); +} + + +meValue me_emit_ptr_offset(meProcedure *p, meValue value, meValue offset) { + Type *ptr_type = me_type(value); + GB_ASSERT(is_type_pointer(ptr_type)); + + meInstruction *v = me_create_instruction(p, meOp_PtrOffset); + v->type = ptr_type; + v->ops[0] = me_use(value); + v->ops[1] = me_use(offset); + v->op_count = 2; + + return me_value(v); +} + +meValue me_emit_ptr_sub(meProcedure *p, meValue ptr0, meValue ptr1) { + Type *p0 = me_type(ptr0); + Type *p1 = me_type(ptr1); + GB_ASSERT(is_type_pointer(p0)); + GB_ASSERT(is_type_pointer(p1)); + GB_ASSERT(are_types_identical(p0, p1)); + + meInstruction *v = me_create_instruction(p, meOp_PtrSub); + v->type = t_int; + v->ops[0] = me_use(ptr0); + v->ops[1] = me_use(ptr1); + v->op_count = 2; + + return me_value(v); +} + +meValue me_emit_conv(meProcedure *p, meValue value, Type *dst_type) { + Type *src_type = me_type(value); + GB_ASSERT(src_type != nullptr); + GB_ASSERT(dst_type != nullptr); + + if (are_types_identical(src_type, dst_type)) { + return value; + } + GB_ASSERT(internal_check_is_castable_to(src_type, dst_type)); + + + meInstruction *v = me_create_instruction(p, meOp_Cast); + v->type = dst_type; + v->ops[0] = me_use(value); + v->op_count = 1; + + return me_value(v); +} + +meValue me_emit_transmute(meProcedure *p, meValue value, Type *dst_type) { + Type *src_type = me_type(value); + GB_ASSERT(src_type != nullptr); + GB_ASSERT(dst_type != nullptr); + + if (are_types_identical(src_type, dst_type)) { + return value; + } + i64 src_sz = type_size_of(src_type); + i64 dst_sz = type_size_of(dst_type); + GB_ASSERT_MSG(src_sz == dst_sz, "%lld != %lld", cast(long long)src_sz, cast(long long)dst_sz); + + meInstruction *v = me_create_instruction(p, meOp_Transmute); + v->type = dst_type; + v->ops[0] = me_use(value); + v->op_count = 1; + + return me_value(v); +} + +meValue me_emit_comp_against_nil(meProcedure *p, meOpKind op, meValue value) { + switch (op) { + case meOp_Eq: + case meOp_NotEq: + break; + default: + GB_PANIC("Invalid comparison against nil op"); + } + + // TODO(bill): me_emit_comp_against_nil + meInstruction *v = me_create_instruction(p, op); + v->type = t_untyped_bool; + v->ops[0] = me_use(value); + v->op_count = 1; + + return me_value(v); +} + + +meValue me_emit_comp(meProcedure *p, meOpKind op, meValue left, meValue right) { + switch (op) { + case meOp_Eq: + case meOp_NotEq: + case meOp_Lt: + case meOp_LtEq: + case meOp_Gt: + case meOp_GtEq: + break; + default: + GB_PANIC("Invalid comparison op"); + } + + Type *lt = me_type(left); + Type *rt = me_type(right); + + Type *a = core_type(lt); + Type *b = core_type(rt); + + meValue nil_check = {}; + if (is_type_untyped_nil(lt)) { + nil_check = me_emit_comp_against_nil(p, op, right); + } else if (is_type_untyped_nil(rt)) { + nil_check = me_emit_comp_against_nil(p, op, left); + } + if (nil_check.kind != meValue_Invalid) { + return nil_check; + } + + + if (are_types_identical(a, b)) { + // NOTE(bill): No need for a conversion + } else if (me_is_const(left) || me_is_const_nil(left)) { + left = me_emit_conv(p, left, rt); + } else if (me_is_const(right) || me_is_const_nil(right)) { + right = me_emit_conv(p, right, lt); + } else { + i64 ls = type_size_of(lt); + i64 rs = type_size_of(rt); + + // NOTE(bill): Quick heuristic, larger types are usually the target type + if (ls < rs) { + left = me_emit_conv(p, left, rt); + } else if (ls > rs) { + right = me_emit_conv(p, right, lt); + } else { + if (is_type_union(rt)) { + left = me_emit_conv(p, left, rt); + } else { + right = me_emit_conv(p, right, lt); + } + } + } + + // TODO(bill): me_emit_comp + + meInstruction *v = me_create_instruction(p, op); + v->type = t_untyped_bool; + v->ops[0] = me_use(left); + v->ops[1] = me_use(right); + v->op_count = 2; + + return me_value(v); +} + + + +meValue me_emit_min(meProcedure *p, meValue left, meValue right) { + Type *lt = me_type(left); + Type *rt = me_type(right); + GB_ASSERT(are_types_identical(lt, rt)); + Type *type = lt; + GB_ASSERT(is_type_ordered(type) && (is_type_numeric(type) || is_type_string(type))); + + // TODO(bill): optimization + meInstruction *v = me_create_instruction(p, meOp_Min); + v->type = type; + v->ops[0] = me_use(left); + v->ops[1] = me_use(right); + v->op_count = 2; + + return me_value(v); +} + +meValue me_emit_max(meProcedure *p, meValue left, meValue right) { + Type *lt = me_type(left); + Type *rt = me_type(right); + GB_ASSERT(are_types_identical(lt, rt)); + Type *type = lt; + GB_ASSERT(is_type_ordered(type) && (is_type_numeric(type) || is_type_string(type))); + + // TODO(bill): optimization + meInstruction *v = me_create_instruction(p, meOp_Max); + v->type = type; + v->ops[0] = me_use(left); + v->ops[1] = me_use(right); + v->op_count = 2; + + return me_value(v); +} + +meValue me_emit_select(meProcedure *p, meValue cond, meValue left, meValue right) { + GB_ASSERT(is_type_boolean(me_type(cond))); + GB_ASSERT(are_types_identical(me_type(left), me_type(right))); + + // TODO(bill): optimization + meInstruction *v = me_create_instruction(p, meOp_Select); + v->type = me_type(left); + v->ops[0] = me_use(cond); + v->ops[1] = me_use(left); + v->ops[2] = me_use(right); + v->op_count = 3; + + return me_value(v); +} + +meValue me_emit_call(meProcedure *p, meValue proc, Slice const &arguments, u16 instruction_flags) { + GB_PANIC("TODO"); + return {}; +} +meValue me_emit_built_call(meProcedure *p, BuiltinProcId id, Slice const &arguments) { + GB_PANIC("TODO"); + return {}; +} + +meValue me_emit_swizzle(meProcedure *p, meValue value, Slice const &arguments) { + GB_PANIC("TODO"); + return {}; +} + + +meValue me_emit_fence(meProcedure *p, meAtomicOrderingKind atomic_ordering) { + GB_PANIC("TODO"); + return {}; +} + +meValue me_emit_atomic_exchange(meProcedure *p, meValue left, meValue right, meAtomicOrderingKind atomic_ordering) { + GB_PANIC("TODO"); + return {}; +} + + +meValue me_emit_atomic_compare_exchange(meProcedure *p, meValue ptr, meValue left, meValue right, meAtomicOrderingKind atomic_ordering) { + GB_PANIC("TODO"); + return {}; +} + + +meValue me_emit_alias(meProcedure *p, meValue value) { + if (value.kind == meValue_Instruction && value.instr->op == meOp_Alias) { + return me_emit_alias(p, value.instr->ops[0]); + } + meInstruction *v = me_create_instruction(p, meOp_Alias); + v->type = me_type(value); + v->ops[0] = me_use(value); + v->op_count = 1; + return me_value(v); +}