aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-03-19 13:03:08 +0000
committergingerBill <bill@gingerbill.org>2022-03-19 13:03:08 +0000
commit16bd6c7205a1eea264cc2daa077f4c7f096868af (patch)
treeb2ac4038bec2d8f1430a7b3b7f0d1a4bd104b098
parent714a5e8931c6113807077dd1653a94437b267708 (diff)
Mock out instructions emit calls
-rw-r--r--src/check_expr.cpp9
-rw-r--r--src/llvm_backend_expr.cpp3
-rw-r--r--src/middle_end.cpp297
-rw-r--r--src/middle_end.hpp95
-rw-r--r--src/middle_end_core.cpp925
5 files changed, 993 insertions, 336 deletions
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<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;
-}
-
+#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 ops[me_INSTRUCTION_MAX_ARG_COUNT];
+ isize op_count;
- meValue *operands[me_INSTRUCTION_MAX_ARG_COUNT];
- isize operand_count;
+ Slice<meValue> *extra_ops; // non-null if used
+};
- Slice<meValue> *extra_operands; // 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<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(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<meValue> const &arguments, u16 instruction_flags) {
+ GB_PANIC("TODO");
+ return {};
+}
+meValue me_emit_built_call(meProcedure *p, BuiltinProcId id, Slice<meValue> const &arguments) {
+ GB_PANIC("TODO");
+ return {};
+}
+
+meValue me_emit_swizzle(meProcedure *p, meValue value, Slice<i32> 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);
+}