diff options
| author | gingerBill <bill@gingerbill.org> | 2017-12-03 20:59:48 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2017-12-03 20:59:48 +0000 |
| commit | 8035a407a6838b1bc3fa1b4c09281c5918cb6bc2 (patch) | |
| tree | 970d77bd3e051cf8db3d1553dd0b21d97d471e61 /src | |
| parent | 97760c3fa4c1d6d01daefefcafbf3e9c757ec983 (diff) | |
Remove dead code
Diffstat (limited to 'src')
| -rw-r--r-- | src/ir_print.cpp | 1 | ||||
| -rw-r--r-- | src/main.cpp | 29 | ||||
| -rw-r--r-- | src/ssa.cpp | 2507 | ||||
| -rw-r--r-- | src/ssa_op.cpp | 275 |
4 files changed, 2 insertions, 2810 deletions
diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3275f0da3..255611fb8 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -466,6 +466,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * // NOTE(bill): Is this correct? Does this handle all cases regarding arrays? if (is_type_array(type) && value.kind != ExactValue_Invalid && + value.kind != ExactValue_String && value.kind != ExactValue_Compound) { i64 count = type->Array.count; Type *elem = type->Array.elem; diff --git a/src/main.cpp b/src/main.cpp index 6dd5ad1f9..d3124528c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,6 @@ #define ALLOW_ARRAY_PROGRAMMING -#define USE_CUSTOM_BACKEND 0 // #define NO_ARRAY_BOUNDS_CHECK -#if !defined(USE_THREADED_PARSER) -#define USE_THREADED_PARSER 0 -#endif #include "common.cpp" #include "timings.cpp" @@ -13,7 +9,6 @@ #include "parser.cpp" #include "docs.cpp" #include "checker.cpp" -#include "ssa.cpp" #include "ir.cpp" #include "ir_opt.cpp" #include "ir_print.cpp" @@ -621,8 +616,6 @@ int main(int arg_count, char **arg_ptr) { Array<String> args = setup_args(arg_count, arg_ptr); -#if 1 - String command = args[1]; String init_filename = {}; @@ -701,7 +694,6 @@ int main(int arg_count, char **arg_ptr) { return 0; } -#if 1 timings_start_section(&timings, str_lit("type check")); Checker checker = {0}; @@ -711,26 +703,11 @@ int main(int arg_count, char **arg_ptr) { check_parsed_files(&checker); - -#endif -#if defined(USE_CUSTOM_BACKEND) && USE_CUSTOM_BACKEND - if (global_error_collector.count != 0) { - return 1; - } - - if (checker.parser->total_token_count < 2) { - return 1; - } - - if (!ssa_generate(&parser, &checker.info)) { - return 1; - } -#else irGen ir_gen = {0}; if (!ir_gen_init(&ir_gen, &checker)) { return 1; } - defer (ir_gen_destroy(&ir_gen)); + // defer (ir_gen_destroy(&ir_gen)); timings_start_section(&timings, str_lit("llvm ir gen")); ir_gen_tree(&ir_gen); @@ -743,7 +720,6 @@ int main(int arg_count, char **arg_ptr) { // prof_print_all(); - #if 1 timings_start_section(&timings, str_lit("llvm-opt")); String output_name = ir_gen.output_name; @@ -994,9 +970,6 @@ int main(int arg_count, char **arg_ptr) { system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base)); } #endif -#endif -#endif -#endif return 0; } diff --git a/src/ssa.cpp b/src/ssa.cpp deleted file mode 100644 index d60425012..000000000 --- a/src/ssa.cpp +++ /dev/null @@ -1,2507 +0,0 @@ -struct ssaModule; -struct ssaValue; -struct ssaValueArgs; -struct ssaDefer; -struct ssaBlock; -struct ssaProc; -struct ssaEdge; -struct ssaRegister; -struct ssaTargetList; - - -String ssa_mangle_name(ssaModule *m, String path, Entity *e); - - -#include "ssa_op.cpp" - -#define SSA_DEFAULT_VALUE_ARG_CAPACITY 8 -struct ssaValueArgs { - ssaValue ** e; - isize count; - isize capacity; - ssaValue * backing[SSA_DEFAULT_VALUE_ARG_CAPACITY]; - gbAllocator allocator; - - ssaValue *&operator[](isize i) { - GB_ASSERT(0 <= i && i <= count); - return e[i]; - } - ssaValue * const &operator[](isize i) const { - GB_ASSERT(0 <= i && i <= count); - return e[i]; - } -}; - -struct ssaValue { - i32 id; // Unique identifier but the pointer could be used too - ssaOp op; // Operation that computes this value - Type * type; - ssaBlock * block; // Containing basic block - - i32 uses; - ssaValueArgs args; - ExactValue exact_value; // Used for constants - - String comment_string; -}; - -enum ssaBlockKind { - ssaBlock_Invalid, - - // NOTE(bill): These are the generic block types and for more specific - // architectures, these could become conditions blocks like amd64 LT or EQ - ssaBlock_Entry, // Entry point - ssaBlock_Plain, - ssaBlock_Defer, // Similar to a plain block but generated by a `defer` statement - ssaBlock_If, - ssaBlock_Ret, - ssaBlock_RetJmp, // Stores return value and jumps to Ret block - ssaBlock_Exit, - - ssaBlock_Count, -}; - -enum ssaBranchPrediction { - ssaBranch_Unknown = 0, - ssaBranch_Likely = +1, - ssaBranch_Unlikely = -1, -}; - -enum ssaDeferKind { - ssaDefer_Node, - ssaDefer_Instr, -}; - -struct ssaDefer { - ssaDeferKind kind; - i32 scope_level; - ssaBlock * block; - union { - AstNode * stmt; - ssaValue * instr; - }; -}; - -enum ssaDeferExitKind { - ssaDeferExit_Default, - ssaDeferExit_Return, - ssaDeferExit_Branch, -}; - -// ssaEdge represents a control flow graph (CFG) edge -struct ssaEdge { - // Succs array: Block To - // Preds array: Block From - ssaBlock *block; - // Index of reverse edge - isize index; -}; - -struct ssaBlock { - i32 id; // Unique identifier but the pointer could be used too - ssaBlockKind kind; - ssaProc * proc; // Containing procedure - String name; // Optional - i32 scope_level; - - // Likely branch direction - ssaBranchPrediction likeliness; - - // Determines how a block exits - // It depends on the type of block: - // - BlockIf will be a boolean value - // - BlockExit will be a memory control value - ssaValue *control; - - Array<ssaValue *> values; - Array<ssaEdge> preds; - Array<ssaEdge> succs; -}; - -struct ssaTargetList { - ssaTargetList *prev; - ssaBlock * break_; - ssaBlock * continue_; - ssaBlock * fallthrough_; -}; - -struct ssaProc { - ssaModule * module; // Parent module - gbAllocator allocator; // Same allocator as the parent module - String name; // Mangled name - Entity * entity; - DeclInfo * decl_info; - - Array<ssaBlock *> blocks; - ssaBlock * entry; // Entry block - ssaBlock * exit; // Exit block - ssaBlock * curr_block; - - ssaTargetList * target_list; - - i32 block_id; - i32 value_id; - Map<ssaValue *> values; // Key: Entity * - - Array<ssaDefer> defer_stmts; - i32 scope_level; -}; - -struct ssaRegister { - i32 id; - i32 size; -}; - -struct ssaModule { - CheckerInfo * info; - gbAllocator allocator; - gbArena arena; - gbAllocator tmp_allocator; - gbArena tmp_arena; - - PtrSet<Entity *> min_dep_map; - Map<ssaValue *> values; // Key: Entity * - // List of registers for the specific architecture - Array<ssaRegister> registers; - - ssaProc *proc; // current procedure - - Entity *entry_point_entity; - - u32 stmt_state_flags; - - Array<ssaProc *> procs; - Array<ssaValue *> procs_to_generate; -}; - -enum ssaAddrKind { - ssaAddr_Default, - ssaAddr_Map, -}; - -struct ssaAddr { - ssaValue * addr; - ssaAddrKind kind; -}; - - - -void ssa_push_target_list(ssaProc *p, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) { - ssaTargetList *tl = gb_alloc_item(p->allocator, ssaTargetList); - tl->prev = p->target_list; - tl->break_ = break_; - tl->continue_ = continue_; - tl->fallthrough_ = fallthrough_; - p->target_list = tl; -} - -void ssa_pop_target_list(ssaProc *p) { - p->target_list = p->target_list->prev; -} - - -ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) { - ssaBlock *b = gb_alloc_item(p->allocator, ssaBlock); - b->id = p->block_id++; - b->kind = kind; - b->proc = p; - p->scope_level = p->scope_level; - if (name != nullptr || name[0] != 0) { - b->name = make_string_c(name); - } - - array_init(&b->values, heap_allocator()); - array_init(&b->preds, heap_allocator()); - array_init(&b->succs, heap_allocator()); - array_add(&p->blocks, b); - return b; -} - -void ssa_clear_block(ssaProc *p, ssaBlock *b) { - GB_ASSERT(b->proc != nullptr); - array_clear(&b->values); - array_clear(&b->preds); - array_clear(&b->succs); - b->proc = nullptr; - b->kind = ssaBlock_Plain; -} - - -void ssa_start_block(ssaProc *p, ssaBlock *b) { - GB_ASSERT(p->curr_block == nullptr); - p->curr_block = b; -} - -ssaBlock *ssa_end_block(ssaProc *p) { - ssaBlock *b = p->curr_block; - if (b == nullptr) { - return nullptr; - } - p->curr_block = nullptr; - return b; -} - -void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) { - if (b == nullptr) { - return; - } - GB_ASSERT(c != nullptr); - isize i = b->succs.count; - isize j = b->preds.count; - ssaEdge s = {c, j}; - ssaEdge p = {b, i}; - array_add(&b->succs, s); - array_add(&c->preds, p); -} - -void ssa_set_control(ssaBlock *b, ssaValue *v) { - if (b->control != nullptr) { - b->control->uses--; - } - b->control = v; - if (v != nullptr) { - v->uses++; - } -} - -void ssa_emit_jump(ssaProc *p, ssaBlock *edge) { - ssa_add_edge_to(ssa_end_block(p), edge); -} - -void ssa_init_value_args(ssaValueArgs *va, gbAllocator a) { - va->e = va->backing; - va->count = 0; - va->capacity = gb_count_of(va->backing); - va->allocator = a; -} - -void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) { - if (va->count >= va->capacity) { - isize capacity = 2*va->capacity; - if (va->e == va->backing) { // Replace the backing with an allocated version instead - ssaValue **new_args = gb_alloc_array(va->allocator, ssaValue *, capacity); - gb_memcopy_array(new_args, va->e, va->count); - va->e = new_args; - } else { - isize old_cap_size = va->capacity * gb_size_of(ssaValue *); - isize new_cap_size = capacity * gb_size_of(ssaValue *); - *(cast(void **)&va->e) = gb_resize(va->allocator, va->e, old_cap_size, new_cap_size); - } - va->capacity = capacity; - } - va->e[va->count++] = arg; arg->uses++; -} - - - -ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) { - GB_ASSERT(b != nullptr); - ssaValue *v = gb_alloc_item(p->allocator, ssaValue); - v->id = p->value_id++; - v->op = op; - v->type = t; - v->block = b; - ssa_init_value_args(&v->args, p->allocator); - array_add(&b->values, v); - return v; -} - -ssaValue *ssa_new_value0(ssaProc *p, ssaOp op, Type *t) { - ssaValue *v = ssa_new_value(p, op, t, p->curr_block); - return v; -} -ssaValue *ssa_new_value0v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) { - ssaValue *v = ssa_new_value0(p, op, t); - v->exact_value = exact_value; - return v; -} - -ssaValue *ssa_new_value1(ssaProc *p, ssaOp op, Type *t, ssaValue *arg) { - ssaValue *v = ssa_new_value(p, op, t, p->curr_block); - ssa_add_arg(&v->args, arg); - return v; -} -ssaValue *ssa_new_value1v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg) { - ssaValue *v = ssa_new_value1(p, op, t, arg); - v->exact_value = exact_value; - return v; -} -ssaValue *ssa_new_value1i(ssaProc *p, ssaOp op, Type *t, i64 i, ssaValue *arg) { - return ssa_new_value1v(p, op, t, exact_value_i64(i), arg); -} - -ssaValue *ssa_new_value2(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1) { - ssaValue *v = ssa_new_value(p, op, t, p->curr_block); - ssa_add_arg(&v->args, arg0); - ssa_add_arg(&v->args, arg1); - return v; -} -ssaValue *ssa_new_value2v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1) { - ssaValue *v = ssa_new_value2(p, op, t, arg0, arg1); - v->exact_value = exact_value; - return v; -} - -ssaValue *ssa_new_value3(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) { - ssaValue *v = ssa_new_value(p, op, t, p->curr_block); - ssa_add_arg(&v->args, arg0); - ssa_add_arg(&v->args, arg1); - ssa_add_arg(&v->args, arg2); - return v; -} -ssaValue *ssa_new_value3v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) { - ssaValue *v = ssa_new_value3(p, op, t, arg0, arg1, arg2); - v->exact_value = exact_value; - return v; -} - -ssaValue *ssa_new_value4(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2, ssaValue *arg3) { - ssaValue *v = ssa_new_value(p, op, t, p->curr_block); - ssa_add_arg(&v->args, arg0); - ssa_add_arg(&v->args, arg1); - ssa_add_arg(&v->args, arg2); - ssa_add_arg(&v->args, arg3); - return v; -} - -ssaValue *ssa_const_val(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) { - return ssa_new_value0v(p, op, t, exact_value); -} - -ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); } -ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_i64(cast(i64)c)); } -ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_i64(cast(i64)c)); } -ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_i64(cast(i64)c)); } -ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_i64(cast(i64)c)); } -ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); } -ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); } -ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); } -ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, empty_exact_value); } -ssaValue *ssa_const_slice (ssaProc *p, Type *t, ExactValue v) { return ssa_const_val(p, ssaOp_ConstSlice, t, v); } -ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, empty_exact_value); } - -ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) { - switch (8*type_size_of(p->allocator, t)) { - case 8: return ssa_const_i8 (p, t, cast(i8)c); - case 16: return ssa_const_i16(p, t, cast(i16)c); - case 32: return ssa_const_i32(p, t, cast(i32)c); - case 64: return ssa_const_i64(p, t, cast(i64)c); - } - GB_PANIC("Unknown int size"); - return nullptr; -} - - - - -ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr); -ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr); -void ssa_build_stmt (ssaProc *p, AstNode *node); -void ssa_build_stmt_list(ssaProc *p, Array<AstNode *> nodes); -ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel); - - - -void ssa_reset_value_args(ssaValue *v) { - for_array(i, v->args) { - v->args[i]->uses--; - } - v->args.count = 0; -} - -void ssa_reset(ssaValue *v, ssaOp op) { - v->op = op; - v->exact_value = empty_exact_value; - ssa_reset_value_args(v); -} - -ssaValue *ssa_get_last_value(ssaBlock *b) { - if (b == nullptr) { - return nullptr; - } - isize len = b->values.count; - if (len <= 0) { - return 0; - } - ssaValue *v = b->values[len-1]; - return v; -} - -void ssa_emit_comment(ssaProc *p, String s) { - // ssa_new_value0v(p, ssaOp_Comment, nullptr, exact_value_string(s)); -} - -void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) { - // ssaValue *last_instr = ssa_get_last_value(p->curr_block); - ssaBlock *b = ssa_new_block(p, ssaBlock_Plain, "defer"); - ssa_emit_jump(p, b); - ssa_start_block(p, b); - ssa_emit_comment(p, str_lit("defer")); - if (d.kind == ssaDefer_Node) { - ssa_build_stmt(p, d.stmt); - } else if (d.kind == ssaDefer_Instr) { - // NOTE(bill): Need to make a new copy - ssaValue *v = cast(ssaValue *)gb_alloc_copy(p->allocator, d.instr, gb_size_of(ssaValue)); - array_add(&p->curr_block->values, v); - } -} - -void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) { - isize count = p->defer_stmts.count; - for (isize i = count-1; i >= 0; i--) { - ssaDefer d = p->defer_stmts[i]; - if (kind == ssaDeferExit_Default) { - gb_printf_err("scope_level %d %d\n", p->scope_level, d.scope_level); - if (p->scope_level == d.scope_level && - d.scope_level > 1) { - ssa_build_defer_stmt(p, d); - array_pop(&p->defer_stmts); - continue; - } else { - break; - } - } else if (kind == ssaDeferExit_Return) { - ssa_build_defer_stmt(p, d); - } else if (kind == ssaDeferExit_Branch) { - GB_ASSERT(b != nullptr); - i32 lower_limit = b->scope_level+1; - if (lower_limit < d.scope_level) { - ssa_build_defer_stmt(p, d); - } - } - } -} - -ssaDefer ssa_add_defer_node(ssaProc *p, i32 scope_level, AstNode *stmt) { - ssaDefer d = {ssaDefer_Node}; - d.scope_level = scope_level; - d.block = p->curr_block; - d.stmt = stmt; - array_add(&p->defer_stmts, d); - return d; -} - -void ssa_open_scope(ssaProc *p) { - p->scope_level++; -} - -void ssa_close_scope(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) { - ssa_emit_defer_stmts(p, kind, b); - GB_ASSERT(p->scope_level > 0); - p->scope_level--; -} - - - - -ssaValue *ssa_emit_load(ssaProc *p, ssaValue *v) { - GB_ASSERT(is_type_pointer(v->type)); - return ssa_new_value1(p, ssaOp_Load, type_deref(v->type), v); -} - -ssaValue *ssa_emit_store(ssaProc *p, ssaValue *dst, ssaValue *v) { - GB_ASSERT(is_type_pointer(dst->type)); -#if 1 - // NOTE(bill): Sanity check - Type *a = core_type(type_deref(dst->type)); - Type *b = core_type(v->type); - if (!is_type_untyped(b)) { - GB_ASSERT_MSG(are_types_identical(a, b), "%s %s", type_to_string(a), type_to_string(b)); - } -#endif - return ssa_new_value2(p, ssaOp_Store, dst->type, dst, v); -} - -bool ssa_is_op_const(ssaOp op) { - switch (op) { - case ssaOp_ConstBool: - case ssaOp_ConstString: - case ssaOp_ConstSlice: - case ssaOp_ConstNil: - case ssaOp_Const8: - case ssaOp_Const16: - case ssaOp_Const32: - case ssaOp_Const64: - case ssaOp_Const32F: - case ssaOp_Const64F: - return true; - } - return false; -} - - - -bool ssa_is_blank_ident(AstNode *node) { - if (node->kind == AstNode_Ident) { - ast_node(i, Ident, node); - return is_blank_ident(i->token.string); - } - return false; -} - - - -ssaAddr ssa_addr(ssaValue *v) { - if (v != nullptr) { - GB_ASSERT(is_type_pointer(v->type)); - } - ssaAddr addr = {0}; - addr.addr = v; - return addr; -} - -Type *ssa_addr_type(ssaAddr addr) { - if (addr.addr == nullptr) { - return nullptr; - } - - if (addr.kind == ssaAddr_Map) { - GB_PANIC("TODO: ssa_addr_type"); - return nullptr; - } - - Type *t = addr.addr->type; - GB_ASSERT(is_type_pointer(t)); - return type_deref(t); -} - - - -ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) { - ssaProc *p = gb_alloc_item(m->allocator, ssaProc); - p->module = m; - p->allocator = m->allocator; - p->name = name; - p->entity = entity; - p->decl_info = decl_info; - - array_init(&p->blocks, heap_allocator()); - array_init(&p->defer_stmts, heap_allocator()); - map_init(&p->values, heap_allocator()); - - return p; -} - -ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { - Type *t = make_type_pointer(p->allocator, e->type); - - ssaBlock *cb = p->curr_block; - p->curr_block = p->entry; - ssaValue *local = ssa_new_value0(p, ssaOp_Local, t); - p->curr_block = cb; - - map_set(&p->values, hash_pointer(e), local); - map_set(&p->module->values, hash_pointer(e), local); - local->comment_string = e->token.string; - ssa_new_value1(p, ssaOp_Zero, t, local); - return ssa_addr(local); -} -ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) { - Entity **found = map_get(&p->module->info->definitions, hash_pointer(name)); - if (found) { - Entity *e = *found; - return ssa_add_local(p, e, name); - } - - return ssa_addr(nullptr); -} - -ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { - GB_ASSERT(t != nullptr); - - Scope *scope = nullptr; - if (p->curr_block) { - // scope = p->curr_block->scope; - } - Entity *e = make_entity_variable(p->allocator, scope, empty_token, t, false); - return ssa_add_local(p, e, nullptr); -} - - - -#define SSA_MAX_STRUCT_FIELD_COUNT 4 - -bool can_ssa_type(Type *t) { - i64 s = type_size_of(heap_allocator(), t); - if (s > 4*build_context.word_size) { - return false; - } - t = core_type(t); - - switch (t->kind) { - case Type_Array: - return t->Array.count == 0; - - case Type_DynamicArray: - return false; - case Type_Map: - return false; - case Type_Tuple: - if (t->Tuple.variables.count > SSA_MAX_STRUCT_FIELD_COUNT) { - return false; - } - for_array(i, t->Tuple.variables) { - if (!can_ssa_type(t->Tuple.variables[i]->type)) { - return false; - } - } - return true; - case Type_Union: - return false; - - case Type_Struct: - if (!t->Struct.is_raw_union) { - if (t->Struct.fields.count > SSA_MAX_STRUCT_FIELD_COUNT) { - return false; - } - for_array(i, t->Struct.fields) { - if (!can_ssa_type(t->Struct.fields[i]->type)) { - return false; - } - } - } - return true; - } - return true; -} - -void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) { - if (addr.addr == nullptr) { - return; - } - if (addr.kind == ssaAddr_Map) { - GB_PANIC("TODO(bill): ssa_addr_store"); - return; - } - - ssa_emit_store(p, addr.addr, value); -} - -ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) { - if (addr.addr == nullptr) { - return nullptr; - } - - if (addr.kind == ssaAddr_Map) { - GB_PANIC("here\n"); - return nullptr; - } - - Type *t = addr.addr->type; - Type *bt = base_type(t); - if (bt->kind == Type_Proc) { - return addr.addr; - } - - return ssa_emit_load(p, addr.addr); -} - -ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) { - GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); - String name = e->token.string; - Entity *parent = e->using_parent; - Selection sel = lookup_field(p->allocator, parent->type, name, false); - GB_ASSERT(sel.entity != nullptr); - ssaValue **pv = map_get(&p->module->values, hash_pointer(parent)); - ssaValue *v = nullptr; - if (pv != nullptr) { - v = *pv; - } else { - v = ssa_build_addr(p, e->using_expr).addr; - } - GB_ASSERT(v != nullptr); - GB_ASSERT(type_deref(v->type) == parent->type); - return ssa_emit_deep_field_ptr_index(p, v, sel); -} - -ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) { - GB_ASSERT(e != nullptr); - - ssaValue *v = nullptr; - ssaValue **found = map_get(&p->module->values, hash_pointer(e)); - if (found) { - v = *found; - } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - // NOTE(bill): Calculate the using variable every time - v = ssa_get_using_variable(p, e); - } - - if (v == nullptr) { - GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind])); - } - - return ssa_addr(v); -} - - -ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) { - Type *src_type = v->type; - if (are_types_identical(t, src_type)) { - return v; - } - - Type *src = core_type(src_type); - Type *dst = core_type(t); - - if (is_type_untyped_nil(src)) { - return ssa_const_nil(p, t); - } - - // Pointer <-> Pointer - if (is_type_pointer(src) && is_type_pointer(dst)) { - return ssa_new_value1(p, ssaOp_Copy, dst, v); - } - // proc <-> proc - if (is_type_proc(src) && is_type_proc(dst)) { - return ssa_new_value1(p, ssaOp_Copy, dst, v); - } - // pointer -> proc - if (is_type_pointer(src) && is_type_proc(dst)) { - return ssa_new_value1(p, ssaOp_Copy, dst, v); - } - // proc -> pointer - if (is_type_proc(src) && is_type_pointer(dst)) { - return ssa_new_value1(p, ssaOp_Copy, dst, v); - } - - - gb_printf_err("ssa_emit_conv: src -> dst\n"); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); - - - GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); - - return nullptr; -} - - -// NOTE(bill): Returns nullptr if not possible -ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) { - if (v->op == ssaOp_Load) { - return v->args[0]; - } - ssaAddr addr = ssa_add_local_generated(p, v->type); - ssa_new_value2(p, ssaOp_Store, addr.addr->type, addr.addr, v); - return addr.addr; -} - - -ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) { - GB_ASSERT(v != nullptr); - GB_ASSERT(is_type_pointer(v->type)); - Type *t = base_type(type_deref(v->type)); - GB_ASSERT_MSG(is_type_array(t), "%s", type_to_string(t)); - Type *elem_ptr = nullptr; - if (is_type_array(t)) { - elem_ptr = make_type_pointer(p->allocator, t->Array.elem); - } - - return ssa_new_value2(p, ssaOp_ArrayIndex, elem_ptr, v, index); -} - -ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) { - gbAllocator a = p->allocator; - Type *t = base_type(type_deref(s->type)); - Type *result_type = nullptr; - - if (is_type_struct(t)) { - GB_ASSERT(t->Struct.fields.count > 0); - result_type = make_type_pointer(a, t->Struct.fields[index]->type); - } else if (is_type_tuple(t)) { - GB_ASSERT(t->Tuple.variables.count > 0); - GB_ASSERT(gb_is_between(index, 0, t->Tuple.variables.count-1)); - result_type = make_type_pointer(a, t->Tuple.variables[index]->type); - } else if (is_type_slice(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->Slice.elem)); break; - case 1: result_type = make_type_pointer(a, t_int); break; - case 2: result_type = make_type_pointer(a, t_int); break; - } - } else if (is_type_string(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, t_u8_ptr); break; - case 1: result_type = make_type_pointer(a, t_int); break; - } - } else if (is_type_any(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, t_type_info_ptr); break; - case 1: result_type = make_type_pointer(a, t_rawptr); break; - } - } else if (is_type_dynamic_array(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break; - case 1: result_type = t_int_ptr; break; - case 2: result_type = t_int_ptr; break; - case 3: result_type = t_allocator_ptr; break; - } - } else if (is_type_map(t)) { - Type *gst = t->Map.generated_struct_type; - switch (index) { - case 0: result_type = make_type_pointer(a, gst->Struct.fields[0]->type); break; - case 1: result_type = make_type_pointer(a, gst->Struct.fields[1]->type); break; - } - }else { - GB_PANIC("TODO(bill): ssa_emit_ptr_index type: %s, %d", type_to_string(s->type), index); - } - - GB_ASSERT(result_type != nullptr); - - return ssa_new_value1i(p, ssaOp_PtrIndex, result_type, index, s); -} -ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) { - if (s->op == ssaOp_Load) { - if (!can_ssa_type(s->type)) { - ssaValue *e = ssa_emit_ptr_index(p, s->args[0], index); - return ssa_emit_load(p, e); - } - } - GB_ASSERT(can_ssa_type(s->type)); - - gbAllocator a = p->allocator; - Type *t = base_type(s->type); - Type *result_type = nullptr; - - if (is_type_struct(t)) { - GB_ASSERT(t->Struct.fields.count > 0); - result_type = t->Struct.fields[index]->type; - } else if (is_type_union(t)) { - type_set_offsets(a, t); - GB_ASSERT(t->Struct.fields.count > 0); - result_type = t->Struct.fields[index]->type; - } else if (is_type_tuple(t)) { - GB_ASSERT(t->Tuple.variables.count > 0); - result_type = t->Tuple.variables[index]->type; - } else if (is_type_slice(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, t->Slice.elem); break; - case 1: result_type = t_int; break; - case 2: result_type = t_int; break; - } - } else if (is_type_string(t)) { - switch (index) { - case 0: result_type = t_u8_ptr; break; - case 1: result_type = t_int; break; - } - } else if (is_type_any(t)) { - switch (index) { - case 0: result_type = t_type_info_ptr; break; - case 1: result_type = t_rawptr; break; - } - } else if (is_type_dynamic_array(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break; - case 1: result_type = t_int; break; - case 2: result_type = t_int; break; - case 3: result_type = t_allocator; break; - } - } else if (is_type_map(t)) { - Type *gst = t->Map.generated_struct_type; - switch (index) { - case 0: result_type = gst->Struct.fields[0]->type; break; - case 1: result_type = gst->Struct.fields[1]->type; break; - } - } else { - GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s->type), index); - } - - GB_ASSERT(result_type != nullptr); - - return ssa_new_value1i(p, ssaOp_ValueIndex, result_type, index, s); -} - - -ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel) { - GB_ASSERT(sel.index.count > 0); - Type *type = type_deref(e->type); - - for_array(i, sel.index) { - i32 index = cast(i32)sel.index[i]; - if (is_type_pointer(type)) { - type = type_deref(type); - e = ssa_emit_load(p, e); - } - type = base_type(type); - - - if (is_type_raw_union(type)) { - type = type->Struct.fields[index]->type; - e = ssa_emit_conv(p, e, make_type_pointer(p->allocator, type)); - } else if (type->kind == Type_Struct) { - type = type->Struct.fields[index]->type; - e = ssa_emit_ptr_index(p, e, index); - } else if (type->kind == Type_Tuple) { - type = type->Tuple.variables[index]->type; - e = ssa_emit_ptr_index(p, e, index); - }else if (type->kind == Type_Basic) { - switch (type->Basic.kind) { - case Basic_any: { - if (index == 0) { - type = t_type_info_ptr; - } else if (index == 1) { - type = t_rawptr; - } - e = ssa_emit_ptr_index(p, e, index); - } break; - - case Basic_string: - e = ssa_emit_ptr_index(p, e, index); - break; - - default: - GB_PANIC("un-gep-able type"); - break; - } - } else if (type->kind == Type_Slice) { - e = ssa_emit_ptr_index(p, e, index); - } else if (type->kind == Type_DynamicArray) { - e = ssa_emit_ptr_index(p, e, index); - } else if (type->kind == Type_Array) { - e = ssa_emit_array_index(p, e, ssa_const_int(p, t_int, index)); - } else if (type->kind == Type_Map) { - e = ssa_emit_ptr_index(p, e, 1); - switch (index) { - case 0: e = ssa_emit_ptr_index(p, e, 1); break; // count - case 1: e = ssa_emit_ptr_index(p, e, 2); break; // capacity - case 2: e = ssa_emit_ptr_index(p, e, 3); break; // allocator - } - } else { - GB_PANIC("un-gep-able type"); - } - } - - return e; -} - -ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel) { - GB_ASSERT(sel.index.count > 0); - Type *type = e->type; - if (e->op == ssaOp_Load) { - if (!can_ssa_type(e->type)) { - ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args[0], sel); - return ssa_emit_load(p, ptr); - } - } - GB_ASSERT(can_ssa_type(e->type)); - - for_array(i, sel.index) { - i32 index = cast(i32)sel.index[i]; - if (is_type_pointer(type)) { - e = ssa_emit_load(p, e); - } - type = base_type(type); - - - if (is_type_raw_union(type)) { - GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); - type = type->Struct.fields[index]->type; - e = ssa_emit_conv(p, e, type); - } else if (type->kind == Type_Map) { - e = ssa_emit_value_index(p, e, 1); - switch (index) { - case 0: e = ssa_emit_value_index(p, e, 1); break; // count - case 1: e = ssa_emit_value_index(p, e, 2); break; // capacity - case 2: e = ssa_emit_value_index(p, e, 3); break; // allocator - } - } else { - e = ssa_emit_value_index(p, e, index); - } - } - - return e; -} - - - - - -ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) { - switch (expr->kind) { - case_ast_node(i, Ident, expr); - if (ssa_is_blank_ident(expr)) { - ssaAddr val = {0}; - return val; - } - Entity *e = entity_of_ident(p->module->info, expr); - return ssa_build_addr_from_entity(p, e, expr); - case_end; - - case_ast_node(pe, ParenExpr, expr); - return ssa_build_addr(p, unparen_expr(expr)); - case_end; - - case_ast_node(se, SelectorExpr, expr); - ssa_emit_comment(p, str_lit("SelectorExpr")); - AstNode *sel = unparen_expr(se->selector); - if (sel->kind == AstNode_Ident) { - String selector = sel->Ident.token.string; - TypeAndValue tav = type_and_value_of_expr(p->module->info, se->expr); - - if (tav.mode == Addressing_Invalid) { - // NOTE(bill): Imports - Entity *imp = entity_of_ident(p->module->info, se->expr); - if (imp != nullptr) { - GB_ASSERT(imp->kind == Entity_ImportName); - } - return ssa_build_addr(p, se->selector); - } - - - Type *type = base_type(tav.type); - if (tav.mode == Addressing_Type) { // Addressing_Type - GB_PANIC("TODO: SelectorExpr Addressing_Type"); - // Selection sel = lookup_field(p->allocator, type, selector, true); - // Entity *e = sel.entity; - // GB_ASSERT(e->kind == Entity_Variable); - // GB_ASSERT(e->flags & EntityFlag_TypeField); - // String name = e->token.string; - // if (name == "names") { - // ssaValue *ti_ptr = ir_type_info(p, type); - - // ssaValue *names_ptr = nullptr; - - // if (is_type_enum(type)) { - // ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr); - // names_ptr = ssa_emit_ptr_index(p, enum_info, 1); - // } else if (type->kind == Type_Struct) { - // ssaValue *struct_info = ssa_emit_conv(p, ti_ptr, t_type_info_struct_ptr); - // names_ptr = ssa_emit_ptr_index(p, struct_info, 1); - // } - // return ssa_addr(names_ptr); - // } else { - // GB_PANIC("Unhandled TypeField %.*s", LIT(name)); - // } - GB_PANIC("Unreachable"); - } - - Selection sel = lookup_field(p->allocator, type, selector, false); - GB_ASSERT(sel.entity != nullptr); - - ssaValue *a = ssa_build_addr(p, se->expr).addr; - a = ssa_emit_deep_field_ptr_index(p, a, sel); - return ssa_addr(a); - } else { - Type *type = base_type(type_of_expr(p->module->info, se->expr)); - GB_ASSERT(is_type_integer(type)); - ExactValue val = type_and_value_of_expr(p->module->info, sel).value; - i64 index = i128_to_i64(val.value_integer); - - Selection sel = lookup_field_from_index(p->allocator, type, index); - GB_ASSERT(sel.entity != nullptr); - - ssaValue *a = ssa_build_addr(p, se->expr).addr; - a = ssa_emit_deep_field_ptr_index(p, a, sel); - return ssa_addr(a); - } - case_end; - - case_ast_node(ue, UnaryExpr, expr); - switch (ue->op.kind) { - case Token_Pointer: { - return ssa_build_addr(p, ue->expr); - } - default: - GB_PANIC("Invalid unary expression for ssa_build_addr"); - } - case_end; - - case_ast_node(be, BinaryExpr, expr); - GB_PANIC("Invalid binary expression for ssa_build_addr: %.*s\n", LIT(be->op.string)); - case_end; - - case_ast_node(ie, IndexExpr, expr); - GB_PANIC("TODO(bill): ssa_build_addr IndexExpr"); - case_end; - - case_ast_node(se, SliceExpr, expr); - GB_PANIC("TODO(bill): ssa_build_addr SliceExpr"); - case_end; - - case_ast_node(de, DerefExpr, expr); - ssaValue *addr = ssa_build_expr(p, de->expr); - return ssa_addr(addr); - case_end; - - case_ast_node(ce, CallExpr, expr); - ssaValue *e = ssa_build_expr(p, expr); - ssaValue *v = ssa_address_from_load_or_generate_local(p, e); - return ssa_addr(v); - case_end; - - case_ast_node(cl, CompoundLit, expr); - GB_PANIC("TODO(bill): ssa_build_addr CompoundLit"); - case_end; - - } - - TokenPos token_pos = ast_node_token(expr).pos; - GB_PANIC("Unexpected address expression\n" - "\tAstNode: %.*s @ " - "%.*s(%td:%td)\n", - LIT(ast_node_strings[expr->kind]), - LIT(token_pos.file), token_pos.line, token_pos.column); - - - return ssa_addr(nullptr); -} - - -Type *ssa_proper_type(Type *t) { - t = default_type(core_type(t)); - - if (t->kind == Type_Basic) { - switch (t->Basic.kind) { - case Basic_int: - if (build_context.word_size == 8) { - return t_i64; - } - return t_i32; - case Basic_uint: - if (build_context.word_size == 8) { - return t_u64; - } - return t_u32; - } - } - - return t; -} - -ssaOp ssa_determine_op(TokenKind op, Type *t) { - t = ssa_proper_type(t); - if (t->kind == Type_Basic) { - switch (t->Basic.kind) { - case Basic_bool: - switch (op) { - case Token_And: return ssaOp_And8; - case Token_Or: return ssaOp_Or8; - case Token_Xor: return ssaOp_Xor8; - case Token_AndNot: return ssaOp_AndNot8; - } - break; - case Basic_i8: - switch (op) { - case Token_Add: return ssaOp_Add8; - case Token_Sub: return ssaOp_Sub8; - case Token_Mul: return ssaOp_Mul8; - case Token_Quo: return ssaOp_Div8; - case Token_Mod: return ssaOp_Mod8; - case Token_And: return ssaOp_And8; - case Token_Or: return ssaOp_Or8; - case Token_Xor: return ssaOp_Xor8; - case Token_AndNot: return ssaOp_AndNot8; - case Token_Lt: return ssaOp_Lt8; - case Token_LtEq: return ssaOp_Le8; - case Token_Gt: return ssaOp_Gt8; - case Token_GtEq: return ssaOp_Ge8; - case Token_CmpEq: return ssaOp_Eq8; - case Token_NotEq: return ssaOp_Ne8; - } - break; - case Basic_u8: - switch (op) { - case Token_Add: return ssaOp_Add8; - case Token_Sub: return ssaOp_Sub8; - case Token_Mul: return ssaOp_Mul8; - case Token_Quo: return ssaOp_Div8U; - case Token_Mod: return ssaOp_Mod8U; - case Token_And: return ssaOp_And8; - case Token_Or: return ssaOp_Or8; - case Token_Xor: return ssaOp_Xor8; - case Token_AndNot: return ssaOp_AndNot8; - case Token_Lt: return ssaOp_Lt8; - case Token_LtEq: return ssaOp_Le8; - case Token_Gt: return ssaOp_Gt8; - case Token_GtEq: return ssaOp_Ge8; - case Token_CmpEq: return ssaOp_Eq8; - case Token_NotEq: return ssaOp_Ne8; - } - break; - case Basic_i16: - switch (op) { - case Token_Add: return ssaOp_Add16; - case Token_Sub: return ssaOp_Sub16; - case Token_Mul: return ssaOp_Mul16; - case Token_Quo: return ssaOp_Div16; - case Token_Mod: return ssaOp_Mod16; - case Token_And: return ssaOp_And16; - case Token_Or: return ssaOp_Or16; - case Token_Xor: return ssaOp_Xor16; - case Token_AndNot: return ssaOp_AndNot16; - case Token_Lt: return ssaOp_Lt16; - case Token_LtEq: return ssaOp_Le16; - case Token_Gt: return ssaOp_Gt16; - case Token_GtEq: return ssaOp_Ge16; - case Token_CmpEq: return ssaOp_Eq16; - case Token_NotEq: return ssaOp_Ne16; - } - break; - case Basic_u16: - switch (op) { - case Token_Add: return ssaOp_Add16; - case Token_Sub: return ssaOp_Sub16; - case Token_Mul: return ssaOp_Mul16; - case Token_Quo: return ssaOp_Div16U; - case Token_Mod: return ssaOp_Mod16U; - case Token_And: return ssaOp_And16; - case Token_Or: return ssaOp_Or16; - case Token_Xor: return ssaOp_Xor16; - case Token_AndNot: return ssaOp_AndNot16; - case Token_Lt: return ssaOp_Lt16; - case Token_LtEq: return ssaOp_Le16; - case Token_Gt: return ssaOp_Gt16; - case Token_GtEq: return ssaOp_Ge16; - case Token_CmpEq: return ssaOp_Eq16; - case Token_NotEq: return ssaOp_Ne16; - } - break; - case Basic_i32: - switch (op) { - case Token_Add: return ssaOp_Add32; - case Token_Sub: return ssaOp_Sub32; - case Token_Mul: return ssaOp_Mul32; - case Token_Quo: return ssaOp_Div32; - case Token_Mod: return ssaOp_Mod32; - case Token_And: return ssaOp_And32; - case Token_Or: return ssaOp_Or32; - case Token_Xor: return ssaOp_Xor32; - case Token_AndNot: return ssaOp_AndNot32; - case Token_Lt: return ssaOp_Lt32; - case Token_LtEq: return ssaOp_Le32; - case Token_Gt: return ssaOp_Gt32; - case Token_GtEq: return ssaOp_Ge32; - case Token_CmpEq: return ssaOp_Eq32; - case Token_NotEq: return ssaOp_Ne32; - } - break; - case Basic_u32: - switch (op) { - case Token_Add: return ssaOp_Add32; - case Token_Sub: return ssaOp_Sub32; - case Token_Mul: return ssaOp_Mul32; - case Token_Quo: return ssaOp_Div32U; - case Token_Mod: return ssaOp_Mod32U; - case Token_And: return ssaOp_And32; - case Token_Or: return ssaOp_Or32; - case Token_Xor: return ssaOp_Xor32; - case Token_AndNot: return ssaOp_AndNot32; - case Token_Lt: return ssaOp_Lt32; - case Token_LtEq: return ssaOp_Le32; - case Token_Gt: return ssaOp_Gt32; - case Token_GtEq: return ssaOp_Ge32; - case Token_CmpEq: return ssaOp_Eq32; - case Token_NotEq: return ssaOp_Ne32; - } - break; - case Basic_i64: - switch (op) { - case Token_Add: return ssaOp_Add64; - case Token_Sub: return ssaOp_Sub64; - case Token_Mul: return ssaOp_Mul64; - case Token_Quo: return ssaOp_Div64; - case Token_Mod: return ssaOp_Mod64; - case Token_And: return ssaOp_And64; - case Token_Or: return ssaOp_Or64; - case Token_Xor: return ssaOp_Xor64; - case Token_AndNot: return ssaOp_AndNot64; - case Token_Lt: return ssaOp_Lt64; - case Token_LtEq: return ssaOp_Le64; - case Token_Gt: return ssaOp_Gt64; - case Token_GtEq: return ssaOp_Ge64; - case Token_CmpEq: return ssaOp_Eq64; - case Token_NotEq: return ssaOp_Ne64; - } - break; - case Basic_u64: - switch (op) { - case Token_Add: return ssaOp_Add64; - case Token_Sub: return ssaOp_Sub64; - case Token_Mul: return ssaOp_Mul64; - case Token_Quo: return ssaOp_Div64U; - case Token_Mod: return ssaOp_Mod64U; - case Token_And: return ssaOp_And64; - case Token_Or: return ssaOp_Or64; - case Token_Xor: return ssaOp_Xor64; - case Token_AndNot: return ssaOp_AndNot64; - case Token_Lt: return ssaOp_Lt64; - case Token_LtEq: return ssaOp_Le64; - case Token_Gt: return ssaOp_Gt64; - case Token_GtEq: return ssaOp_Ge64; - case Token_CmpEq: return ssaOp_Eq64; - case Token_NotEq: return ssaOp_Ne64; - } - break; - case Basic_f32: - switch (op) { - case Token_Add: return ssaOp_Add32F; - case Token_Sub: return ssaOp_Sub32F; - case Token_Mul: return ssaOp_Mul32F; - case Token_Quo: return ssaOp_Div32F; - case Token_Lt: return ssaOp_Lt32F; - case Token_LtEq: return ssaOp_Le32F; - case Token_Gt: return ssaOp_Gt32F; - case Token_GtEq: return ssaOp_Ge32F; - case Token_CmpEq: return ssaOp_Eq32F; - case Token_NotEq: return ssaOp_Ne32F; - } - break; - case Basic_f64: - switch (op) { - case Token_Add: return ssaOp_Add64F; - case Token_Sub: return ssaOp_Sub64F; - case Token_Mul: return ssaOp_Mul64F; - case Token_Quo: return ssaOp_Div64F; - case Token_Lt: return ssaOp_Lt64F; - case Token_LtEq: return ssaOp_Le64F; - case Token_Gt: return ssaOp_Gt64F; - case Token_GtEq: return ssaOp_Ge64F; - case Token_CmpEq: return ssaOp_Eq64F; - case Token_NotEq: return ssaOp_Ne64F; - } - break; - } - } - - GB_PANIC("Invalid Op for type"); - return ssaOp_Invalid; -} - - -ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) { - GB_ASSERT(x != nullptr && y != nullptr); - Type *a = core_type(x->type); - Type *b = core_type(y->type); - if (are_types_identical(a, b)) { - // NOTE(bill): No need for a conversion - } else if (ssa_is_op_const(x->op)) { - x = ssa_emit_conv(p, x, y->type); - } else if (ssa_is_op_const(y->op)) { - y = ssa_emit_conv(p, y, x->type); - } - - Type *result = t_bool; - - return ssa_new_value2(p, ssa_determine_op(op, x->type), x->type, x, y); -} - - - -ssaValue *ssa_emit_unary_arith(ssaProc *p, TokenKind op, ssaValue *x, Type *type) { - switch (op) { - case Token_Pointer: { - GB_PANIC("Token_Pointer should be handled elsewhere"); - } break; - - case Token_Add: - return x; - - case Token_Not: // Boolean not - return ssa_new_value1(p, ssaOp_NotB, type, x); - case Token_Xor: { // Bitwise not - isize bits = 8*type_size_of(p->allocator, x->type); - switch (bits) { - case 8: return ssa_new_value1(p, ssaOp_Not8, type, x); - case 16: return ssa_new_value1(p, ssaOp_Not16, type, x); - case 32: return ssa_new_value1(p, ssaOp_Not32, type, x); - case 64: return ssa_new_value1(p, ssaOp_Not64, type, x); - } - GB_PANIC("unknown integer size"); - } break; - - case Token_Sub: { // 0-x - isize bits = 8*type_size_of(p->allocator, x->type); - if (is_type_integer(x->type)) { - switch (bits) { - case 8: return ssa_new_value1(p, ssaOp_Neg8, type, x); - case 16: return ssa_new_value1(p, ssaOp_Neg16, type, x); - case 32: return ssa_new_value1(p, ssaOp_Neg32, type, x); - case 64: return ssa_new_value1(p, ssaOp_Neg64, type, x); - } - } else if (is_type_float(x->type)) { - switch (bits) { - case 32: return ssa_new_value1(p, ssaOp_Neg32F, type, x); - case 64: return ssa_new_value1(p, ssaOp_Neg64F, type, x); - } - } - GB_PANIC("unknown type for -x"); - } break; - } - return nullptr; -} -ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) { - if (is_type_complex(x->type)) { - GB_PANIC("TODO(bill): ssa_emit_arith complex"); - } - - if (op == Token_Add) { - if (is_type_pointer(x->type)) { - GB_PANIC("TODO(bill): Ptr arith"); - ssaValue *ptr = ssa_emit_conv(p, x, type); - ssaValue *offset = y; - // return ssa_emit_ptr_offset(p, ptr, offset); - } else if (is_type_pointer(y->type)) { - GB_PANIC("TODO(bill): Ptr arith"); - - ssaValue *ptr = ssa_emit_conv(p, y, type); - ssaValue *offset = x; - // return ssa_emit_ptr_offset(p, ptr, offset); - } - } else if (op == Token_Sub) { - if (is_type_pointer(x->type) && is_type_integer(y->type)) { - GB_PANIC("TODO(bill): Ptr arith"); - // ptr - int - ssaValue *ptr = ssa_emit_conv(p, x, type); - ssaValue *offset = y; - // return ssa_emit_ptr_offset(p, ptr, offset); - } else if (is_type_pointer(x->type) && is_type_pointer(y->type)) { - GB_ASSERT(is_type_integer(type)); - Type *ptr_type = base_type(x->type); - GB_ASSERT(!is_type_rawptr(ptr_type)); - ssaValue *elem_size = ssa_const_int(p, t_int, type_size_of(p->allocator, ptr_type->Pointer.elem)); - ssaValue *a = ssa_emit_conv(p, x, type); - ssaValue *b = ssa_emit_conv(p, y, type); - ssaValue *diff = ssa_emit_arith(p, op, a, b, type); - return ssa_emit_arith(p, Token_Quo, diff, elem_size, type); - } - } - - switch (op) { - case Token_Add: - case Token_Sub: - case Token_Mul: - case Token_Quo: - case Token_Mod: - case Token_And: - case Token_Or: - case Token_Xor: - case Token_AndNot: - GB_ASSERT(x != nullptr && y != nullptr); - return ssa_new_value2(p, ssa_determine_op(op, x->type), type, x, y); - } - - return nullptr; -} - - - - -ssaValue *ssa_build_cond(ssaProc *p, AstNode *cond, ssaBlock *yes, ssaBlock *no) { - switch (cond->kind) { - case_ast_node(pe, ParenExpr, cond); - return ssa_build_cond(p, pe->expr, yes, no); - case_end; - - case_ast_node(ue, UnaryExpr, cond); - if (ue->op.kind == Token_Not) { - return ssa_build_cond(p, ue->expr, no, yes); - } - case_end; - - case_ast_node(be, BinaryExpr, cond); - if (be->op.kind == Token_CmpAnd) { - ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmd.and"); - ssa_build_cond(p, be->left, block, no); - ssa_start_block(p, block); - return ssa_build_cond(p, be->right, yes, no); - } else if (be->op.kind == Token_CmpOr) { - ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmp.or"); - ssa_build_cond(p, be->left, yes, block); - ssa_start_block(p, block); - return ssa_build_cond(p, be->right, yes, no); - } - case_end; - } - - ssaValue *c = ssa_build_expr(p, cond); - ssaBlock *b = ssa_end_block(p); - b->kind = ssaBlock_If; - ssa_set_control(b, c); - ssa_add_edge_to(b, yes); - ssa_add_edge_to(b, no); - return c; -} - -ssaValue *ssa_emit_logical_binary_expr(ssaProc *p, AstNode *expr) { - ast_node(be, BinaryExpr, expr); - - ssaBlock *rhs = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.rhs"); - ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.done"); - - GB_ASSERT(p->curr_block != nullptr); - - Type *type = default_type(type_of_expr(p->module->info, expr)); - - bool short_circuit_value = false; - if (be->op.kind == Token_CmpAnd) { - ssa_build_cond(p, be->left, rhs, done); - short_circuit_value = false; - } else if (be->op.kind == Token_CmpOr) { - ssa_build_cond(p, be->left, done, rhs); - short_circuit_value = true; - } - if (rhs->preds.count == 0) { - ssa_start_block(p, done); - return ssa_const_bool(p, type, short_circuit_value); - } - - if (done->preds.count == 0) { - ssa_start_block(p, rhs); - return ssa_build_expr(p, be->right); - } - - ssa_start_block(p, rhs); - ssaValue *short_circuit = ssa_const_bool(p, type, short_circuit_value); - ssaValueArgs edges = {0}; - ssa_init_value_args(&edges, p->allocator); - for_array(i, done->preds) { - ssa_add_arg(&edges, short_circuit); - } - - ssa_add_arg(&edges, ssa_build_expr(p, be->right)); - ssa_emit_jump(p, done); - ssa_start_block(p, done); - - ssaValue *phi = ssa_new_value0(p, ssaOp_Phi, type); - phi->args = edges; - return phi; -} - -ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { - expr = unparen_expr(expr); - - TypeAndValue tv = type_and_value_of_expr(p->module->info, expr); - GB_ASSERT(tv.mode != Addressing_Invalid); - - if (tv.value.kind != ExactValue_Invalid) { - Type *t = core_type(tv.type); - if (is_type_boolean(t)) { - return ssa_const_bool(p, tv.type, tv.value.value_bool); - } else if (is_type_string(t)) { - GB_ASSERT(tv.value.kind == ExactValue_String); - return ssa_const_string(p, tv.type, tv.value.value_string); - } else if(is_type_slice(t)) { - return ssa_const_slice(p, tv.type, tv.value); - } else if (is_type_integer(t)) { - GB_ASSERT(tv.value.kind == ExactValue_Integer); - - i64 s = 8*type_size_of(p->allocator, t); - switch (s) { - case 8: return ssa_const_i8 (p, tv.type, cast (i8)i128_to_i64(tv.value.value_integer)); - case 16: return ssa_const_i16(p, tv.type, cast(i16)i128_to_i64(tv.value.value_integer)); - case 32: return ssa_const_i32(p, tv.type, cast(i32)i128_to_i64(tv.value.value_integer)); - case 64: return ssa_const_i64(p, tv.type, cast(i64)i128_to_i64(tv.value.value_integer)); - default: GB_PANIC("Unknown integer size"); - } - } else if (is_type_float(t)) { - GB_ASSERT(tv.value.kind == ExactValue_Float); - i64 s = 8*type_size_of(p->allocator, t); - switch (s) { - case 32: return ssa_const_f32(p, tv.type, cast(f32)tv.value.value_float); - case 64: return ssa_const_f64(p, tv.type, cast(f64)tv.value.value_float); - default: GB_PANIC("Unknown float size"); - } - } - // IMPORTANT TODO(bill): Do constant str/array literals correctly - return ssa_const_nil(p, tv.type); - } - - if (tv.mode == Addressing_Variable) { - return ssa_addr_load(p, ssa_build_addr(p, expr)); - } - - - switch (expr->kind) { - case_ast_node(bl, BasicLit, expr); - GB_PANIC("Non-constant basic literal"); - case_end; - - case_ast_node(bd, BasicDirective, expr); - TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name)); - case_end; - - case_ast_node(i, Ident, expr); - Entity *e = *map_get(&p->module->info->uses, hash_pointer(expr)); - if (e->kind == Entity_Builtin) { - Token token = ast_node_token(expr); - GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n" - "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name), - LIT(token.pos.file), token.pos.line, token.pos.column); - return nullptr; - } else if (e->kind == Entity_Nil) { - GB_PANIC("TODO(bill): nil"); - return nullptr; - } - - ssaValue **found = map_get(&p->module->values, hash_pointer(e)); - if (found) { - ssaValue *v = *found; - if (v->op == ssaOp_Proc) { - return v; - } - - ssaAddr addr = ssa_build_addr(p, expr); - return ssa_addr_load(p, addr); - } - case_end; - - case_ast_node(ue, UnaryExpr, expr); - if (ue->op.kind == Token_Pointer) { - return ssa_build_addr(p, ue->expr).addr; - } - ssaValue *x = ssa_build_expr(p, ue->expr); - return ssa_emit_unary_arith(p, ue->op.kind, x, tv.type); - - case_end; - - case_ast_node(be, BinaryExpr, expr); - Type *type = default_type(tv.type); - - switch (be->op.kind) { - case Token_Add: - case Token_Sub: - case Token_Mul: - case Token_Quo: - case Token_Mod: - case Token_And: - case Token_Or: - case Token_Xor: - case Token_AndNot: { - ssaValue *x = ssa_build_expr(p, be->left); - ssaValue *y = ssa_build_expr(p, be->right); - return ssa_emit_arith(p, be->op.kind, x, y, type); - } - - case Token_Shl: - case Token_Shr: { - GB_PANIC("TODO: shifts"); - return nullptr; - } - - case Token_CmpEq: - case Token_NotEq: - case Token_Lt: - case Token_LtEq: - case Token_Gt: - case Token_GtEq: { - ssaValue *x = ssa_build_expr(p, be->left); - ssaValue *y = ssa_build_expr(p, be->right); - return ssa_emit_comp(p, be->op.kind, x, y); - } break; - - case Token_CmpAnd: - case Token_CmpOr: - return ssa_emit_logical_binary_expr(p, expr); - - default: - GB_PANIC("Invalid binary expression"); - break; - } - case_end; - - case_ast_node(de, DerefExpr, expr); - return ssa_addr_load(p, ssa_build_addr(p, expr)); - case_end; - - case_ast_node(se, SelectorExpr, expr); - return ssa_addr_load(p, ssa_build_addr(p, expr)); - case_end; - - case_ast_node(te, TernaryExpr, expr); - ssa_emit_comment(p, str_lit("TernaryExpr")); - - ssaValue *yes = nullptr; - ssaValue *no = nullptr; - - GB_ASSERT(te->y != nullptr); - ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then"); - ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); // NOTE(bill): Append later - ssaBlock *else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); - - ssaBlock *v = nullptr; - - ssa_build_cond(p, te->cond, then, else_); - ssa_start_block(p, then); - - // ssa_open_scope(p); - yes = ssa_build_expr(p, te->x); - // ssa_close_scope(p, ssaDeferExit_Default, nullptr); - - ssa_emit_jump(p, done); - ssa_start_block(p, else_); - - // ssa_open_scope(p); - no = ssa_build_expr(p, te->y); - // ssa_close_scope(p, ssaDeferExit_Default, nullptr); - - ssa_emit_jump(p, done); - ssa_start_block(p, done); - - return ssa_new_value2(p, ssaOp_Phi, tv.type, yes, no); - case_end; - - - case_ast_node(pl, ProcLit, expr); - GB_PANIC("TODO(bill): ssa_build_expr ProcLit"); - #if 0 - // NOTE(bill): Generate a new name - // parent$count - isize name_len = proc->name.len + 1 + 8 + 1; - u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)proc->children.count); - String name = make_string(name_text, name_len-1); - - Type *type = type_of_expr(proc->module->info, expr); - irValue *value = ir_value_procedure(proc->module->allocator, - proc->module, nullptr, type, pl->type, pl->body, name); - - value->Proc.tags = pl->tags; - value->Proc.parent = proc; - - array_add(&proc->children, &value->Proc); - array_add(&proc->module->procs_to_generate, value); - - return value; - #endif - case_end; - - case_ast_node(cl, CompoundLit, expr); - return ssa_addr_load(p, ssa_build_addr(p, expr)); - case_end; - - - case_ast_node(ce, CallExpr, expr); - if (map_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { - GB_ASSERT(ce->args.count == 1); - ssaValue *x = ssa_build_expr(p, ce->args[0]); - return ssa_emit_conv(p, x, tv.type); - } - - AstNode *p = unparen_expr(ce->proc); - GB_PANIC("TODO(bill): ssa_build_expr CallExpr"); - case_end; - - case_ast_node(se, SliceExpr, expr); - return ssa_addr_load(p, ssa_build_addr(p, expr)); - case_end; - - case_ast_node(ie, IndexExpr, expr); - return ssa_addr_load(p, ssa_build_addr(p, expr)); - case_end; - } - - GB_PANIC("Unexpected expression: %.*s", LIT(ast_node_strings[expr->kind])); - - return nullptr; -} - - - -void ssa_build_stmt_list(ssaProc *p, Array<AstNode *> nodes) { - for_array(i, nodes) { - ssa_build_stmt(p, nodes[i]); - } -} - - - -void ssa_build_when_stmt(ssaProc *p, AstNodeWhenStmt *ws) { - ssaValue *cond = ssa_build_expr(p, ws->cond); - GB_ASSERT(is_type_boolean(cond->type)); - - GB_ASSERT(cond->exact_value.kind == ExactValue_Bool); - if (cond->exact_value.value_bool) { - ssa_build_stmt_list(p, ws->body->BlockStmt.stmts); - } else if (ws->else_stmt) { - switch (ws->else_stmt->kind) { - case AstNode_BlockStmt: - ssa_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); - break; - case AstNode_WhenStmt: - ssa_build_when_stmt(p, &ws->else_stmt->WhenStmt); - break; - default: - GB_PANIC("Invalid `else` statement in `when` statement"); - break; - } - } -} - -void ssa_build_assign_op(ssaProc *p, ssaAddr lhs, ssaValue *value, TokenKind op) { - ssaValue *old_value = ssa_addr_load(p, lhs); - Type *type = old_value->type; - - ssaValue *change = value; - if (is_type_pointer(type) && is_type_integer(value->type)) { - change = ssa_emit_conv(p, value, default_type(value->type)); - } else { - change = ssa_emit_conv(p, value, type); - } - ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type); - ssa_addr_store(p, lhs, new_value); -} - -void ssa_build_stmt_internal(ssaProc *p, AstNode *node); -void ssa_build_stmt(ssaProc *p, AstNode *node) { - u32 prev_stmt_state_flags = p->module->stmt_state_flags; - - if (node->stmt_state_flags != 0) { - u32 in = node->stmt_state_flags; - u32 out = p->module->stmt_state_flags; - - if (in & StmtStateFlag_bounds_check) { - out |= StmtStateFlag_bounds_check; - out &= ~StmtStateFlag_no_bounds_check; - } else if (in & StmtStateFlag_no_bounds_check) { - out |= StmtStateFlag_no_bounds_check; - out &= ~StmtStateFlag_bounds_check; - } - - p->module->stmt_state_flags = out; - } - - ssa_build_stmt_internal(p, node); - - p->module->stmt_state_flags = prev_stmt_state_flags; -} -void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { - if (p->curr_block == nullptr) { - ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, ""); - ssa_start_block(p, dead_block); - } - - switch (node->kind) { - case_ast_node(es, EmptyStmt, node); - case_end; - - case_ast_node(bs, BlockStmt, node); - ssa_open_scope(p); - ssa_build_stmt_list(p, bs->stmts); - ssa_close_scope(p, ssaDeferExit_Default, nullptr); - case_end; - - case_ast_node(us, UsingStmt, node); - case_end; - - case_ast_node(ws, WhenStmt, node); - ssa_build_when_stmt(p, ws); - case_end; - - #if 0 - case_ast_node(s, IncDecStmt, node); - TokenKind op = Token_Add; - if (s->op.kind == Token_Dec) { - op = Token_Sub; - } - ssaAddr addr = ssa_build_addr(p, s->expr); - Type *t = ssa_addr_type(addr); - ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op); - case_end; - #endif - - case_ast_node(as, AssignStmt, node); - ssa_emit_comment(p, str_lit("AssignStmt")); - - ssaModule *m = p->module; - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); - - switch (as->op.kind) { - case Token_Eq: { - Array<ssaAddr> lvals = {0}; - array_init(&lvals, m->tmp_allocator); - - for_array(i, as->lhs) { - AstNode *lhs = as->lhs[i]; - ssaAddr lval = {0}; - if (!ssa_is_blank_ident(lhs)) { - lval = ssa_build_addr(p, lhs); - } - array_add(&lvals, lval); - } - - if (as->lhs.count == as->rhs.count) { - if (as->lhs.count == 1) { - AstNode *rhs = as->rhs[0]; - ssaValue *init = ssa_build_expr(p, rhs); - ssa_addr_store(p, lvals[0], init); - } else { - Array<ssaValue *> inits; - array_init(&inits, m->tmp_allocator, lvals.count); - - for_array(i, as->rhs) { - ssaValue *init = ssa_build_expr(p, as->rhs[i]); - array_add(&inits, init); - } - - for_array(i, inits) { - ssa_addr_store(p, lvals[i], inits[i]); - } - } - } else { - Array<ssaValue *> inits; - array_init(&inits, m->tmp_allocator, lvals.count); - - for_array(i, as->rhs) { - ssaValue *init = ssa_build_expr(p, as->rhs[i]); - Type *t = base_type(init->type); - // TODO(bill): refactor for code reuse as this is repeated a bit - if (t->kind == Type_Tuple) { - for_array(i, t->Tuple.variables) { - Entity *e = t->Tuple.variables[i]; - ssaValue *v = ssa_emit_value_index(p, init, i); - array_add(&inits, v); - } - } else { - array_add(&inits, init); - } - } - - for_array(i, inits) { - ssa_addr_store(p, lvals[i], inits[i]); - } - } - } break; - - default: { - // GB_PANIC("TODO(bill): assign operations"); - // NOTE(bill): Only 1 += 1 is allowed, no tuples - // +=, -=, etc - i32 op = cast(i32)as->op.kind; - op += Token_Add - Token_AddEq; // Convert += to + - ssaAddr lhs = ssa_build_addr(p, as->lhs[0]); - ssaValue *value = ssa_build_expr(p, as->rhs[0]); - ssa_build_assign_op(p, lhs, value, cast(TokenKind)op); - } break; - } - - gb_temp_arena_memory_end(tmp); - case_end; - - case_ast_node(es, ExprStmt, node); - // NOTE(bill): No need to use return value - ssa_build_expr(p, es->expr); - case_end; - - case_ast_node(ds, DeferStmt, node); - // GB_PANIC("TODO: DeferStmt"); - ssa_emit_comment(p, str_lit("DeferStmt")); - i32 scope_level = p->scope_level; - if (ds->stmt->kind == AstNode_BlockStmt) { - scope_level--; - } - ssa_add_defer_node(p, scope_level, ds->stmt); - case_end; - - case_ast_node(rs, ReturnStmt, node); - GB_PANIC("TODO: ReturnStmt"); - case_end; - - case_ast_node(is, IfStmt, node); - ssa_emit_comment(p, str_lit("IfStmt")); - if (is->init != nullptr) { - ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init"); - ssa_emit_jump(p, init); - ssa_start_block(p, init); - ssa_build_stmt(p, is->init); - } - ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then"); - ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); - ssaBlock *else_ = done; - if (is->else_stmt != nullptr) { - else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); - } - ssaBlock *b = nullptr; - - ssa_build_cond(p, is->cond, then, else_); - ssa_start_block(p, then); - - ssa_open_scope(p); - ssa_build_stmt(p, is->body); - ssa_close_scope(p, ssaDeferExit_Default, nullptr); - - ssa_emit_jump(p, done); - - if (is->else_stmt != nullptr) { - ssa_start_block(p, else_); - - ssa_open_scope(p); - ssa_build_stmt(p, is->else_stmt); - ssa_close_scope(p, ssaDeferExit_Default, nullptr); - - ssa_emit_jump(p, done); - } - - ssa_start_block(p, done); - case_end; - - - case_ast_node(fs, ForStmt, node); - ssa_emit_comment(p, str_lit("ForStmt")); - if (fs->init != nullptr) { - ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init"); - ssa_emit_jump(p, init); - ssa_start_block(p, init); - ssa_build_stmt(p, fs->init); - } - - ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body"); - ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done"); - ssaBlock *loop = body; - if (fs->cond != nullptr) { - loop = ssa_new_block(p, ssaBlock_Plain, "for.loop"); - } - ssaBlock *post = loop; - if (fs->post != nullptr) { - post = ssa_new_block(p, ssaBlock_Plain, "for.post"); - } - - ssa_emit_jump(p, loop); - ssa_start_block(p, loop); - - if (loop != body) { - ssa_build_cond(p, fs->cond, body, done); - ssa_start_block(p, body); - } - - ssa_push_target_list(p, done, post, nullptr); - ssa_open_scope(p); - ssa_build_stmt(p, fs->body); - ssa_close_scope(p, ssaDeferExit_Default, nullptr); - ssa_pop_target_list(p); - - ssa_emit_jump(p, post); - - if (fs->post != nullptr) { - ssa_start_block(p, post); - ssa_build_stmt(p, fs->post); - ssa_emit_jump(p, post); - } - - ssa_start_block(p, done); - case_end; - - case_ast_node(rs, RangeStmt, node); - GB_PANIC("TODO: RangeStmt"); - case_end; - - case_ast_node(rs, SwitchStmt, node); - GB_PANIC("TODO: SwitchStmt"); - case_end; - - case_ast_node(rs, TypeSwitchStmt, node); - GB_PANIC("TODO: TypeSwitchStmt"); - case_end; - - case_ast_node(bs, BranchStmt, node); - ssaBlock *b = nullptr; - switch (bs->token.kind) { - case Token_break: - for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) { - b = t->break_; - } - break; - case Token_continue: - for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) { - b = t->continue_; - } - break; - case Token_fallthrough: - for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) { - b = t->fallthrough_; - } - break; - } - if (b != nullptr) { - ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b); - } - switch (bs->token.kind) { - case Token_break: ssa_emit_comment(p, str_lit("break")); break; - case Token_continue: ssa_emit_comment(p, str_lit("continue")); break; - case Token_fallthrough: ssa_emit_comment(p, str_lit("fallthrough")); break; - } - ssa_emit_jump(p, b); - case_end; - - case_ast_node(pc, PushContext, node); - GB_PANIC("TODO: PushContext"); - case_end; - } -} - -void ssa_print_value(gbFile *f, ssaValue *v) { - if (v == nullptr) { - gb_fprintf(f, "nil"); - } - gb_fprintf(f, "v%d", v->id); -} - -void ssa_print_exact_value(gbFile *f, ssaValue *v) { - Type *t = default_type(v->type); - ExactValue ev = v->exact_value; - switch (ev.kind) { - case ExactValue_Bool: - if (ev.value_bool == false) { - gb_fprintf(f, " [false]"); - } else { - gb_fprintf(f, " [true]"); - } - break; - case ExactValue_Integer: - if (is_type_unsigned(t)) { - gb_fprintf(f, " [%llu]", cast(unsigned long long)i128_to_u64(ev.value_integer)); - } else { - gb_fprintf(f, " [%lld]", cast(long long)i128_to_i64(ev.value_integer)); - } - break; - case ExactValue_Float: - if (is_type_f32(t)) { - f32 fp = cast(f32)ev.value_float; - u32 x = *cast(u32 *)&fp; - gb_fprintf(f, " [0x%x]", x); - } else if (is_type_f64(t)) { - f64 fp = cast(f64)ev.value_float; - u64 x = *cast(u64 *)&fp; - gb_fprintf(f, " [0x%llx]", cast(unsigned long long)x); - } else { - GB_PANIC("unhandled float"); - } - break; - case ExactValue_String: - gb_fprintf(f, " [%.*s]", LIT(ev.value_string)); - break; - case ExactValue_Pointer: - gb_fprintf(f, " [0x%llx]", cast(unsigned long long)cast(uintptr)ev.value_pointer); - break; - } -} - - -void ssa_print_reg_value(gbFile *f, ssaValue *v) { - gb_fprintf(f, " "); - gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op])); - - if (v->type != nullptr) { - gbString type_str = type_to_string(default_type(v->type)); - gb_fprintf(f, " %s", type_str); - gb_string_free(type_str); - } - - ssa_print_exact_value(f, v); - - for_array(i, v->args) { - gb_fprintf(f, " "); - ssa_print_value(f, v->args[i]); - } - - if (v->comment_string.len > 0) { - gb_fprintf(f, " ; %.*s", LIT(v->comment_string)); - } - - gb_fprintf(f, "\n"); - -} - -void ssa_print_proc(gbFile *f, ssaProc *p) { - gbString type_str = type_to_string(p->entity->type); - gb_fprintf(f, "%.*s %s\n", LIT(p->name), type_str); - gb_string_free(type_str); - - bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1); - - for_array(i, p->blocks) { - ssaBlock *b = p->blocks[i]; - gb_fprintf(f, " b%d:", b->id); - if (b->preds.count > 0) { - gb_fprintf(f, " <-"); - for_array(j, b->preds) { - ssaBlock *pred = b->preds[j].block; - gb_fprintf(f, " b%d", pred->id); - } - } - if (b->name.len > 0) { - gb_fprintf(f, " ; %.*s", LIT(b->name)); - } - gb_fprintf(f, "\n"); - - isize n = 0; - for_array(j, b->values) { - ssaValue *v = b->values[j]; - if (v->op != ssaOp_Phi) { - continue; - } - ssa_print_reg_value(f, v); - printed[v->id] = true; - n++; - } - - while (n < b->values.count) { - isize m = 0; - for_array(j, b->values) { - ssaValue *v = b->values[j]; - if (printed[v->id]) { - continue; - } - bool skip = false; - for_array(k, v->args) { - ssaValue *w = v->args[k]; - if (w != nullptr && w->block == b && !printed[w->id]) { - skip = true; - break; - } - } - - if (skip) { - break; - } - - ssa_print_reg_value(f, v); - printed[v->id] = true; - n++; - } - if (m == n) { - gb_fprintf(f, "!!!!DepCycle!!!!\n"); - for_array(k, b->values) { - ssaValue *v = b->values[k]; - if (printed[v->id]) { - continue; - } - - ssa_print_reg_value(f, v); - printed[v->id] = true; - n++; - } - } - } - - if (b->kind == ssaBlock_Plain) { - GB_ASSERT(b->succs.count == 1); - ssaBlock *next = b->succs[0].block; - gb_fprintf(f, " "); - gb_fprintf(f, "jump b%d", next->id); - gb_fprintf(f, "\n"); - } else if (b->kind == ssaBlock_If) { - GB_ASSERT(b->succs.count == 2); - ssaBlock *yes = b->succs[0].block; - ssaBlock *no = b->succs[1].block; - gb_fprintf(f, " "); - gb_fprintf(f, "branch v%d, b%d, b%d", b->control->id, yes->id, no->id); - gb_fprintf(f, "\n"); - } else if (b->kind == ssaBlock_Exit) { - gb_fprintf(f, " "); - gb_fprintf(f, "exit"); - gb_fprintf(f, "\n"); - } else if (b->kind == ssaBlock_Ret) { - gb_fprintf(f, " "); - gb_fprintf(f, "ret"); - gb_fprintf(f, "\n"); - } - } - - gb_free(heap_allocator(), printed); -} - - -void ssa_opt_proc(ssaProc *p) { -} - -void ssa_build_proc(ssaModule *m, ssaProc *p) { - p->module = m; - m->proc = p; - - if (p->decl_info->proc_lit == nullptr || - p->decl_info->proc_lit->kind != AstNode_ProcLit) { - return; - } - - ast_node(pl, ProcLit, p->decl_info->proc_lit); - if (pl->body == nullptr) { - return; - } - p->entry = ssa_new_block(p, ssaBlock_Entry, "entry"); - - ssa_start_block(p, p->entry); - ssa_build_stmt(p, pl->body); - - if (p->entity->type->Proc.result_count == 0) { - ssa_emit_defer_stmts(p, ssaDeferExit_Return, nullptr); - } - - p->exit = ssa_new_block(p, ssaBlock_Exit, "exit"); - ssa_emit_jump(p, p->exit); - - ssa_opt_proc(p); - - ssa_print_proc(gb_file_get_standard(gbFileStandard_Error), p); -} - - - -bool ssa_generate(Parser *parser, CheckerInfo *info) { - if (global_error_collector.count != 0) { - return false; - } - - ssaModule m = {0}; - { // Init ssaModule - m.info = info; - - isize token_count = parser->total_token_count; - isize arena_size = 4 * token_count * gb_max3(gb_size_of(ssaValue), gb_size_of(ssaBlock), gb_size_of(ssaProc)); - - gb_arena_init_from_allocator(&m.arena, heap_allocator(), arena_size); - gb_arena_init_from_allocator(&m.tmp_arena, heap_allocator(), arena_size); - m.tmp_allocator = gb_arena_allocator(&m.tmp_arena); - m.allocator = gb_arena_allocator(&m.arena); - - map_init(&m.values, heap_allocator()); - array_init(&m.registers, heap_allocator()); - array_init(&m.procs, heap_allocator()); - array_init(&m.procs_to_generate, heap_allocator()); - } - - isize global_variable_max_count = 0; - Entity *entry_point = nullptr; - bool has_dll_main = false; - bool has_win_main = false; - - for_array(i, info->entities.entries) { - auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)entry->key.ptr; - String name = e->token.string; - if (e->kind == Entity_Variable) { - global_variable_max_count++; - } else if (e->kind == Entity_Procedure && !e->scope->is_global) { - if (e->scope->is_init && name == "main") { - entry_point = e; - } - if (e->Procedure.is_export || - (e->Procedure.link_name.len > 0) || - (e->scope->is_file && e->Procedure.link_name.len > 0)) { - if (!has_dll_main && name == "DllMain") { - has_dll_main = true; - } else if (!has_win_main && name == "WinMain") { - has_win_main = true; - } - } - } - } - - - m.entry_point_entity = entry_point; - m.min_dep_map = generate_minimum_dependency_set(info, entry_point); - - for_array(i, info->entities.entries) { - auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)entry->key.ptr; - String name = e->token.string; - DeclInfo *decl = entry->value; - Scope *scope = e->scope; - - if (!scope->is_file) { - continue; - } - - if (!ptr_set_exists(&m.min_dep_map, e)) { - // NOTE(bill): Nothing depends upon it so doesn't need to be built - continue; - } - - if (!scope->is_global) { - if (e->kind == Entity_Procedure && e->Procedure.is_export) { - } else if (e->kind == Entity_Variable && e->Variable.is_export) { - } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { - // Handle later - } else if (scope->is_init && e->kind == Entity_Procedure && name == "main") { - } else { - name = ssa_mangle_name(&m, e->token.pos.file, e); - } - } - - - switch (e->kind) { - case Entity_TypeName: - break; - - case Entity_Variable: { - - } break; - - case Entity_Procedure: { - ast_node(pl, ProcLit, decl->proc_lit); - String original_name = name; - AstNode *body = pl->body; - if (e->Procedure.is_foreign) { - name = e->token.string; // NOTE(bill): Don't use the mangled name - } - if (e->Procedure.link_name.len > 0) { - name = e->Procedure.link_name; - } - - if (e == entry_point) { - ssaProc *p = ssa_new_proc(&m, name, e, decl); - ssa_build_proc(&m, p); - } - - // ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); - // p->Proc.tags = pl->tags; - - // ssa_module_add_value(m, e, p); - // HashKey hash_name = hash_string(name); - // if (map_get(&m.members, hash_name) == nullptr) { - // map_set(&m.members, hash_name, p); - // } - } break; - } - } - - return true; -} - - - - - - -String ssa_mangle_name(ssaModule *m, String path, Entity *e) { - // NOTE(bill): prefix names not in the init scope - // TODO(bill): make robust and not just rely on the file's name - String name = e->token.string; - CheckerInfo *info = m->info; - gbAllocator a = m->allocator; - AstFile *file = *map_get(&info->files, hash_string(path)); - - char *str = gb_alloc_array(a, char, path.len+1); - gb_memmove(str, path.text, path.len); - str[path.len] = 0; - for (isize i = 0; i < path.len; i++) { - if (str[i] == '\\') { - str[i] = '/'; - } - } - - char const *base = gb_path_base_name(str); - char const *ext = gb_path_extension(base); - isize base_len = ext-1-base; - - isize max_len = base_len + 1 + 10 + 1 + name.len; - bool is_overloaded = check_is_entity_overloaded(e); - if (is_overloaded) { - max_len += 21; - } - - u8 *new_name = gb_alloc_array(a, u8, max_len); - isize new_name_len = gb_snprintf( - cast(char *)new_name, max_len, - "%.*s-%u.%.*s", - cast(int)base_len, base, - cast(u32)file->id, - LIT(name)); - if (is_overloaded) { - char *str = cast(char *)new_name + new_name_len-1; - isize len = max_len-new_name_len; - isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e); - new_name_len += extra-1; - } - - return make_string(new_name, new_name_len-1); -} diff --git a/src/ssa_op.cpp b/src/ssa_op.cpp deleted file mode 100644 index c62e7cf77..000000000 --- a/src/ssa_op.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#define SSA_OPS \ - SSA_OP(Invalid)\ -\ - SSA_OP(Unknown)\ -\ - SSA_OP(Comment) /* Does nothing */\ -\ - SSA_OP(SP) /* Stack Pointer */\ - SSA_OP(SB) /* Stack Base */\ -\ - SSA_OP(Local)\ - SSA_OP(Global)\ - SSA_OP(Proc)\ -\ - SSA_OP(Load)\ - SSA_OP(Store)\ - SSA_OP(Move)\ - SSA_OP(LoadReg)\ - SSA_OP(StoreReg)\ - SSA_OP(Zero) /* Zero initialize */\ -\ - SSA_OP(ArrayIndex) /* Index for a fixed array */\ - SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\ - SSA_OP(PtrOffset)\ - SSA_OP(ValueIndex) /* Extract for a value from a register */\ -\ - SSA_OP(Phi)\ - SSA_OP(Copy)\ -\ - /* TODO(bill): calling conventions */\ - SSA_OP(CallOdin)\ - SSA_OP(CallC)\ - SSA_OP(CallStd)\ - SSA_OP(CallFast)\ -\ - SSA_OP(BoundsCheck)\ - SSA_OP(SliceBoundsCheck)\ -\ - /* Built in operations/procedures */\ - SSA_OP(Bswap16)\ - SSA_OP(Bswap32)\ - SSA_OP(Bswap64)\ -\ - SSA_OP(Assume)\ - SSA_OP(DebugTrap)\ - SSA_OP(Trap)\ - SSA_OP(ReadCycleCounter)\ -\ -\ - SSA_OP(ConstBool)\ - SSA_OP(ConstString)\ - SSA_OP(ConstSlice)\ - SSA_OP(ConstNil)\ - SSA_OP(Const8)\ - SSA_OP(Const16)\ - SSA_OP(Const32)\ - SSA_OP(Const64)\ - SSA_OP(Const32F)\ - SSA_OP(Const64F)\ -\ - /* These should be all the operations I could possibly need for the mean time */\ - SSA_OP(Add8)\ - SSA_OP(Add16)\ - SSA_OP(Add32)\ - SSA_OP(Add64)\ - SSA_OP(AddPtr)\ - SSA_OP(Add32F)\ - SSA_OP(Add64F)\ - SSA_OP(Sub8)\ - SSA_OP(Sub16)\ - SSA_OP(Sub32)\ - SSA_OP(Sub64)\ - SSA_OP(SubPtr)\ - SSA_OP(Sub32F)\ - SSA_OP(Sub64F)\ - SSA_OP(Mul8)\ - SSA_OP(Mul16)\ - SSA_OP(Mul32)\ - SSA_OP(Mul64)\ - SSA_OP(Mul32F)\ - SSA_OP(Mul64F)\ - SSA_OP(Div8)\ - SSA_OP(Div8U)\ - SSA_OP(Div16)\ - SSA_OP(Div16U)\ - SSA_OP(Div32)\ - SSA_OP(Div32U)\ - SSA_OP(Div64)\ - SSA_OP(Div64U)\ - SSA_OP(Div32F)\ - SSA_OP(Div64F)\ - SSA_OP(Mod8)\ - SSA_OP(Mod8U)\ - SSA_OP(Mod16)\ - SSA_OP(Mod16U)\ - SSA_OP(Mod32)\ - SSA_OP(Mod32U)\ - SSA_OP(Mod64)\ - SSA_OP(Mod64U)\ -\ - SSA_OP(And8)\ - SSA_OP(And16)\ - SSA_OP(And32)\ - SSA_OP(And64)\ - SSA_OP(Or8)\ - SSA_OP(Or16)\ - SSA_OP(Or32)\ - SSA_OP(Or64)\ - SSA_OP(Xor8)\ - SSA_OP(Xor16)\ - SSA_OP(Xor32)\ - SSA_OP(Xor64)\ - SSA_OP(AndNot8)\ - SSA_OP(AndNot16)\ - SSA_OP(AndNot32)\ - SSA_OP(AndNot64)\ -\ - SSA_OP(Lsh8x8)\ - SSA_OP(Lsh8x16)\ - SSA_OP(Lsh8x32)\ - SSA_OP(Lsh8x64)\ - SSA_OP(Lsh16x8)\ - SSA_OP(Lsh16x16)\ - SSA_OP(Lsh16x32)\ - SSA_OP(Lsh16x64)\ - SSA_OP(Lsh32x8)\ - SSA_OP(Lsh32x16)\ - SSA_OP(Lsh32x32)\ - SSA_OP(Lsh32x64)\ - SSA_OP(Lsh64x8)\ - SSA_OP(Lsh64x16)\ - SSA_OP(Lsh64x32)\ - SSA_OP(Lsh64x64)\ - SSA_OP(Rsh8x8)\ - SSA_OP(Rsh8x16)\ - SSA_OP(Rsh8x32)\ - SSA_OP(Rsh8x64)\ - SSA_OP(Rsh16x8)\ - SSA_OP(Rsh16x16)\ - SSA_OP(Rsh16x32)\ - SSA_OP(Rsh16x64)\ - SSA_OP(Rsh32x8)\ - SSA_OP(Rsh32x16)\ - SSA_OP(Rsh32x32)\ - SSA_OP(Rsh32x64)\ - SSA_OP(Rsh64x8)\ - SSA_OP(Rsh64x16)\ - SSA_OP(Rsh64x32)\ - SSA_OP(Rsh64x64)\ - SSA_OP(Rsh8Ux8)\ - SSA_OP(Rsh8Ux16)\ - SSA_OP(Rsh8Ux32)\ - SSA_OP(Rsh8Ux64)\ - SSA_OP(Rsh16Ux8)\ - SSA_OP(Rsh16Ux16)\ - SSA_OP(Rsh16Ux32)\ - SSA_OP(Rsh16Ux64)\ - SSA_OP(Rsh32Ux8)\ - SSA_OP(Rsh32Ux16)\ - SSA_OP(Rsh32Ux32)\ - SSA_OP(Rsh32Ux64)\ - SSA_OP(Rsh64Ux8)\ - SSA_OP(Rsh64Ux16)\ - SSA_OP(Rsh64Ux32)\ - SSA_OP(Rsh64Ux64)\ -\ - SSA_OP(Eq8)\ - SSA_OP(Eq16)\ - SSA_OP(Eq32)\ - SSA_OP(Eq64)\ - SSA_OP(EqPtr)\ - SSA_OP(Eq32F)\ - SSA_OP(Eq64F)\ - SSA_OP(Ne8)\ - SSA_OP(Ne16)\ - SSA_OP(Ne32)\ - SSA_OP(Ne64)\ - SSA_OP(NePtr)\ - SSA_OP(Ne32F)\ - SSA_OP(Ne64F)\ - SSA_OP(Lt8)\ - SSA_OP(Lt16)\ - SSA_OP(Lt32)\ - SSA_OP(Lt64)\ - SSA_OP(LtPtr)\ - SSA_OP(Lt32F)\ - SSA_OP(Lt64F)\ - SSA_OP(Gt8)\ - SSA_OP(Gt16)\ - SSA_OP(Gt32)\ - SSA_OP(Gt64)\ - SSA_OP(GtPtr)\ - SSA_OP(Gt32F)\ - SSA_OP(Gt64F)\ - SSA_OP(Le8)\ - SSA_OP(Le16)\ - SSA_OP(Le32)\ - SSA_OP(Le64)\ - SSA_OP(LePtr)\ - SSA_OP(Le32F)\ - SSA_OP(Le64F)\ - SSA_OP(Ge8)\ - SSA_OP(Ge16)\ - SSA_OP(Ge32)\ - SSA_OP(Ge64)\ - SSA_OP(GePtr)\ - SSA_OP(Ge32F)\ - SSA_OP(Ge64F)\ -\ - SSA_OP(NotB)\ - SSA_OP(EqB)\ - SSA_OP(NeB)\ -\ - SSA_OP(Neg8)\ - SSA_OP(Neg16)\ - SSA_OP(Neg32)\ - SSA_OP(Neg64)\ - SSA_OP(Neg32F)\ - SSA_OP(Neg64F)\ -\ - SSA_OP(Not8)\ - SSA_OP(Not16)\ - SSA_OP(Not32)\ - SSA_OP(Not64)\ -\ - SSA_OP(SignExt8to16)\ - SSA_OP(SignExt8to32)\ - SSA_OP(SignExt8to64)\ - SSA_OP(SignExt16to32)\ - SSA_OP(SignExt16to64)\ - SSA_OP(SignExt32to64)\ - SSA_OP(ZeroExt8to16)\ - SSA_OP(ZeroExt8to32)\ - SSA_OP(ZeroExt8to64)\ - SSA_OP(ZeroExt16to32)\ - SSA_OP(ZeroExt16to64)\ - SSA_OP(ZeroExt32to64)\ - SSA_OP(Trunc16to8)\ - SSA_OP(Trunc32to8)\ - SSA_OP(Trunc32to16)\ - SSA_OP(Trunc64to8)\ - SSA_OP(Trunc64to16)\ - SSA_OP(Trunc64to32)\ -\ - SSA_OP(Cvt32to32F)\ - SSA_OP(Cvt32to64F)\ - SSA_OP(Cvt64to32F)\ - SSA_OP(Cvt64to64F)\ - SSA_OP(Cvt32Fto32)\ - SSA_OP(Cvt32Fto64)\ - SSA_OP(Cvt64Fto32)\ - SSA_OP(Cvt64Fto64)\ - SSA_OP(Cvt32Fto64F)\ - SSA_OP(Cvt64Fto32F)\ - SSA_OP(Cvt32Uto32F)\ - SSA_OP(Cvt32Uto64F)\ - SSA_OP(Cvt32Fto32U)\ - SSA_OP(Cvt64Fto32U)\ - SSA_OP(Cvt64Uto32F)\ - SSA_OP(Cvt64Uto64F)\ - SSA_OP(Cvt32Fto64U)\ - SSA_OP(Cvt64Fto64U)\ - - -enum ssaOp { -#define SSA_OP(k) GB_JOIN2(ssaOp_, k), - SSA_OPS -#undef SSA_OP -}; - -String const ssa_op_strings[] = { -#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1}, - SSA_OPS -#undef SSA_OP -}; |