From 09f39ae2ccea78ecd37facc5431c51e4c9666630 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Wed, 26 Oct 2016 20:10:32 +0100 Subject: [PATCH] Better constant strings for SSA; Fix Type_Info --- code/demo.odin | 4 +- src/checker/checker.cpp | 14 ++-- src/checker/expr.cpp | 17 ++-- src/checker/stmt.cpp | 2 +- src/checker/types.cpp | 5 +- src/common.cpp | 23 ++++-- src/llvm/ssa_to_text.cpp | 132 ++++++++++++++++++++++++------ src/ssa/build.cpp | 131 +++++++----------------------- src/ssa/codegen.cpp | 27 +++---- src/ssa/emit.cpp | 145 ++++++++++++++------------------- src/ssa/make.cpp | 169 +++++++++++++++++++++++++++++++-------- src/ssa/ssa.cpp | 45 ++++++++--- 12 files changed, 420 insertions(+), 294 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 5d84f9340..d714907e3 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,8 +1,10 @@ #import "fmt.odin" +str := "Hellope" + a: [12]u8 main :: proc() { v: [4]f32 v[0] = 123 - fmt.println("Hellope!", v, v[0], a) + fmt.println(str, v, v[0], a) } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index e7286fbb9..4beaca6d3 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -200,7 +200,7 @@ struct CheckerInfo { Map foreign_procs; // Key: String Map files; // Key: String (full path) Map type_info_map; // Key: Type * - isize type_info_index; + isize type_info_count; Entity * implicit_values[ImplicitValue_Count]; }; @@ -536,7 +536,7 @@ void init_checker_info(CheckerInfo *i) { map_init(&i->foreign_procs, a); map_init(&i->type_info_map, a); map_init(&i->files, a); - i->type_info_index = 0; + i->type_info_count = 0; } @@ -736,19 +736,21 @@ void add_type_info_type(Checker *c, Type *t) { Type *prev_type = cast(Type *)e->key.ptr; if (are_types_identical(t, prev_type)) { // Duplicate entry - ti_index = i; + ti_index = e->value; break; } } if (ti_index < 0) { // Unique entry // NOTE(bill): map entries grow linearly and in order - ti_index = c->info.type_info_index; - c->info.type_info_index++; + ti_index = c->info.type_info_count; + c->info.type_info_count++; } map_set(&c->info.type_info_map, hash_pointer(t), ti_index); + + // Add nested types if (t->kind == Type_Named) { @@ -758,6 +760,8 @@ void add_type_info_type(Checker *c, Type *t) { } Type *bt = base_type(t); + add_type_info_type(c, bt); + switch (bt->kind) { case Type_Basic: { switch (bt->Basic.kind) { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index dbddfd33e..9024d3c9e 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -248,16 +248,17 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, CycleChecker *cycle_checker, String context) { PROF_PROC(); + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + Map entity_map = {}; - map_init(&entity_map, heap_allocator()); - defer (map_destroy(&entity_map)); + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(field_count+other_field_count)); + // defer (map_destroy(&entity_map)); isize other_field_index = 0; Entity *using_index_expr = NULL; - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); struct Delay { Entity *e; AstNode *t; @@ -661,9 +662,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod GB_ASSERT(is_type_enum(enum_type)); ast_node(et, EnumType, node); + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + Map entity_map = {}; - map_init(&entity_map, heap_allocator()); - defer (map_destroy(&entity_map)); + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count)); + // defer (map_destroy(&entity_map)); Type *base_type = t_int; if (et->base_type != NULL) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 6c0ffb356..a4647fc29 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -633,7 +633,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Token token; }; - Map seen = {}; // Multimap + Map seen = {}; // NOTE(bill): Multimap map_init(&seen, heap_allocator()); defer (map_destroy(&seen)); for_array(i, bs->stmts) { diff --git a/src/checker/types.cpp b/src/checker/types.cpp index c606f189c..e216e556d 100644 --- a/src/checker/types.cpp +++ b/src/checker/types.cpp @@ -1347,7 +1347,7 @@ gbString write_type_to_string(gbString str, Type *type) { for (isize i = 1; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; GB_ASSERT(f->kind == Entity_TypeName); - if (i > 0) { + if (i > 1) { str = gb_string_appendc(str, "; "); } str = gb_string_append_length(str, f->token.string.text, f->token.string.len); @@ -1362,8 +1362,9 @@ gbString write_type_to_string(gbString str, Type *type) { for (isize i = 0; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) + if (i > 0) { str = gb_string_appendc(str, ", "); + } str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_appendc(str, ": "); str = write_type_to_string(str, f->type); diff --git a/src/common.cpp b/src/common.cpp index 44ee869cb..d0703378c 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -215,14 +215,15 @@ struct Map { Array > entries; }; -template void map_init (Map *h, gbAllocator a); -template void map_destroy(Map *h); -template T * map_get (Map *h, HashKey key); -template void map_set (Map *h, HashKey key, T value); -template void map_remove (Map *h, HashKey key); -template void map_clear (Map *h); -template void map_grow (Map *h); -template void map_rehash (Map *h, isize new_count); +template void map_init (Map *h, gbAllocator a); +template void map_init_with_reserve(Map *h, gbAllocator a, isize capacity); +template void map_destroy (Map *h); +template T * map_get (Map *h, HashKey key); +template void map_set (Map *h, HashKey key, T value); +template void map_remove (Map *h, HashKey key); +template void map_clear (Map *h); +template void map_grow (Map *h); +template void map_rehash (Map *h, isize new_count); template MapEntry *multi_map_find_first(Map *h, HashKey key); template MapEntry *multi_map_find_next (Map *h, MapEntry *e); @@ -242,6 +243,12 @@ gb_inline void map_init(Map *h, gbAllocator a) { array_init(&h->entries, a); } +template +gb_inline void map_init_with_reserve(Map *h, gbAllocator a, isize capacity) { + array_init(&h->hashes, a, capacity); + array_init(&h->entries, a, capacity); +} + template gb_inline void map_destroy(Map *h) { array_free(&h->entries); diff --git a/src/llvm/ssa_to_text.cpp b/src/llvm/ssa_to_text.cpp index 210607ea6..71cd8baf4 100644 --- a/src/llvm/ssa_to_text.cpp +++ b/src/llvm/ssa_to_text.cpp @@ -1,9 +1,11 @@ b32 ssa_valid_char(u8 c) { - if (c >= 0x80) + if (c >= 0x80) { return false; + } - if (gb_char_is_alphanumeric(c)) + if (gb_char_is_alphanumeric(c)) { return true; + } switch (c) { case '$': @@ -20,8 +22,9 @@ void ssa_print_escape_string(ssaFileBuffer *f, String name, b32 print_quotes) { isize extra = 0; for (isize i = 0; i < name.len; i++) { u8 c = name.text[i]; - if (!ssa_valid_char(c)) + if (!ssa_valid_char(c)) { extra += 2; + } } if (extra == 0) { @@ -185,7 +188,9 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { } else { ssa_fprintf(f, "{"); for (isize i = 0; i < t->Tuple.variable_count; i++) { - if (i > 0) ssa_fprintf(f, ", "); + if (i > 0) { + ssa_fprintf(f, ", "); + } ssa_print_type(f, m, t->Tuple.variables[i]->type); } ssa_fprintf(f, "}"); @@ -225,23 +230,6 @@ void ssa_print_compound_element(ssaFileBuffer *f, ssaModule *m, ExactValue v, Ty if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) { ssa_fprintf(f, "zeroinitializer"); - } else if (v.kind == ExactValue_String) { - // HACK NOTE(bill): This is a hack but it works because strings are created at the very end - // of the .ll file - ssaValue *str_array = ssa_add_global_string_array(m, v.value_string); - - ssa_fprintf(f, "{i8* getelementptr inbounds ("); - ssa_print_type(f, m, str_array->Global.entity->type); - ssa_fprintf(f, ", "); - ssa_print_type(f, m, str_array->Global.entity->type); - ssa_fprintf(f, "* "); - ssa_print_encoded_global(f, str_array->Global.entity->token.string, false); - ssa_fprintf(f, ", "); - ssa_print_type(f, m, t_int); - ssa_fprintf(f, " 0, i32 0), "); - ssa_print_type(f, m, t_int); - ssa_fprintf(f, " %lld}", cast(i64)v.value_string.len); - } else { ssa_print_exact_value(f, m, v, elem_type); } @@ -269,9 +257,33 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ ssa_fprintf(f, "%s", (value.value_bool ? "true" : "false")); break; case ExactValue_String: { - ssa_fprintf(f, "c\""); - ssa_print_escape_string(f, value.value_string, false); - ssa_fprintf(f, "\""); + String str = value.value_string; + if (str.len == 0) { + ssa_fprintf(f, "zeroinitializer"); + break; + } + if (!is_type_string(type)) { + GB_ASSERT(is_type_array(type)); + ssa_fprintf(f, "c\""); + ssa_print_escape_string(f, str, false); + ssa_fprintf(f, "\""); + } else { + // HACK NOTE(bill): This is a hack but it works because strings are created at the very end + // of the .ll file + ssaValue *str_array = ssa_add_global_string_array(m, str); + + ssa_fprintf(f, "{i8* getelementptr inbounds ("); + ssa_print_type(f, m, str_array->Global.entity->type); + ssa_fprintf(f, ", "); + ssa_print_type(f, m, str_array->Global.entity->type); + ssa_fprintf(f, "* "); + ssa_print_encoded_global(f, str_array->Global.entity->token.string, false); + ssa_fprintf(f, ", "); + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " 0, i32 0), "); + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " %lld}", cast(i64)str.len); + } } break; case ExactValue_Integer: { if (is_type_pointer(type)) { @@ -954,6 +966,78 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, "\n"); } break; + case ssaInstr_BoundsCheck: { + auto *bc = &instr->BoundsCheck; + ssa_fprintf(f, "call void "); + ssa_print_encoded_global(f, make_string("__bounds_check_error"), false); + ssa_fprintf(f, "("); + ssa_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_value(f, m, bc->index, t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_value(f, m, bc->len, t_int); + + ssa_fprintf(f, ")\n"); + } break; + + case ssaInstr_SliceBoundsCheck: { + auto *bc = &instr->SliceBoundsCheck; + ssa_fprintf(f, "call void "); + if (bc->is_substring) { + ssa_print_encoded_global(f, make_string("__substring_expr_error"), false); + } else { + ssa_print_encoded_global(f, make_string("__slice_expr_error"), false); + } + + ssa_fprintf(f, "("); + ssa_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_value(f, m, bc->low, t_int); + ssa_fprintf(f, ", "); + + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_value(f, m, bc->high, t_int); + + if (!bc->is_substring) { + ssa_fprintf(f, ", "); + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " "); + ssa_print_value(f, m, bc->max, t_int); + } + + ssa_fprintf(f, ")\n"); + } break; + default: { GB_PANIC(" %d\n", instr->kind); diff --git a/src/ssa/build.cpp b/src/ssa/build.cpp index 737ce3a22..31ced6a76 100644 --- a/src/ssa/build.cpp +++ b/src/ssa/build.cpp @@ -85,42 +85,6 @@ void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) { } -void ssa_array_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ssaValue *len) { - if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { - return; - } - - gbAllocator a = proc->module->allocator; - ssaValue **args = gb_alloc_array(a, ssaValue *, 5); - args[0] = ssa_emit_global_string(proc, token.pos.file); - args[1] = ssa_make_const_int(a, token.pos.line); - args[2] = ssa_make_const_int(a, token.pos.column); - args[3] = ssa_emit_conv(proc, index, t_int); - args[4] = ssa_emit_conv(proc, len, t_int); - - ssa_emit_global_call(proc, "__bounds_check_error", args, 5); -} - -void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) { - if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { - return; - } - - gbAllocator a = proc->module->allocator; - ssaValue **args = gb_alloc_array(a, ssaValue *, 6); - args[0] = ssa_emit_global_string(proc, token.pos.file); - args[1] = ssa_make_const_int(a, token.pos.line); - args[2] = ssa_make_const_int(a, token.pos.column); - args[3] = ssa_emit_conv(proc, low, t_int); - args[4] = ssa_emit_conv(proc, high, t_int); - args[5] = ssa_emit_conv(proc, max, t_int); - - if (!is_substring) { - ssa_emit_global_call(proc, "__slice_expr_error", args, 6); - } else { - ssa_emit_global_call(proc, "__substring_expr_error", args, 5); - } -} ssaValue *ssa_find_global_variable(ssaProcedure *proc, String name) { ssaValue **value = map_get(&proc->module->members, hash_string(name)); @@ -498,13 +462,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue *elem_size = ssa_make_const_int(allocator, s); ssaValue *elem_align = ssa_make_const_int(allocator, a); - ssaValue *len =ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[1]), t_int); + ssaValue *len = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[1]), t_int); ssaValue *cap = len; if (ce->args.count == 3) { cap = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[2]), t_int); } - ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false); + ssa_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false); ssaValue *slice_size = ssa_emit_arith(proc, Token_Mul, elem_size, cap, t_int); @@ -548,10 +512,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue expr_str.len = expr_len; ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4); - args[0] = ssa_emit_global_string(proc, pos.file); + args[0] = ssa_make_const_string(proc->module->allocator, pos.file); args[1] = ssa_make_const_int(proc->module->allocator, pos.line); args[2] = ssa_make_const_int(proc->module->allocator, pos.column); - args[3] = ssa_emit_global_string(proc, expr_str); + args[3] = ssa_make_const_string(proc->module->allocator, expr_str); ssa_emit_global_call(proc, "__assert", args, 4); ssa_emit_jump(proc, done); @@ -569,7 +533,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue TokenPos pos = token.pos; ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4); - args[0] = ssa_emit_global_string(proc, pos.file); + args[0] = ssa_make_const_string(proc->module->allocator, pos.file); args[1] = ssa_make_const_int(proc->module->allocator, pos.line); args[2] = ssa_make_const_int(proc->module->allocator, pos.column); args[3] = msg; @@ -904,16 +868,6 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) { GB_ASSERT_NOT_NULL(tv); if (tv->value.kind != ExactValue_Invalid) { - if (tv->value.kind == ExactValue_String) { - ssa_emit_comment(proc, make_string("Emit string constant")); - if (tv->value.value_string.len > 0) { - return ssa_emit_global_string(proc, tv->value.value_string); - } else { - ssaValue *null_string = ssa_add_local_generated(proc, t_string); - return ssa_emit_load(proc, null_string); - } - } - return ssa_add_module_constant(proc->module, tv->type, tv->value); } @@ -957,21 +911,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { Entity *e = entity_of_ident(proc->module->info, expr); TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(expr)); - if (e->kind == Entity_Constant) { - if (base_type(e->type) == t_string) { - // HACK TODO(bill): This is lazy but it works - String str = e->Constant.value.value_string; - ssaValue *global_array = ssa_add_global_string_array(proc->module, str); - ssaValue *elem = ssa_array_elem(proc, global_array); - ssaValue *len = ssa_make_const_int(proc->module->allocator, str.len); - ssaValue *v = ssa_add_local_generated(proc, e->type); - ssaValue *str_elem = ssa_emit_struct_ep(proc, v, 0); - ssaValue *str_len = ssa_emit_struct_ep(proc, v, 1); - ssa_emit_store(proc, str_elem, elem); - ssa_emit_store(proc, str_len, len); - return ssa_make_addr(v, expr); - } - } + GB_ASSERT(e->kind != Entity_Constant); ssaValue *v = NULL; ssaValue **found = map_get(&proc->module->values, hash_pointer(e)); @@ -1087,7 +1027,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { } ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); ssaValue *len = ssa_make_const_int(a, t->Vector.count); - ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len); + ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len); return ssa_make_addr_vector(vector, index, expr); } break; @@ -1104,7 +1044,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); ssaValue *elem = ssa_emit_array_ep(proc, array, index); ssaValue *len = ssa_make_const_int(a, t->Vector.count); - ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len); + ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len); return ssa_make_addr(elem, expr); } break; @@ -1121,7 +1061,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue *elem = ssa_slice_elem(proc, slice); ssaValue *len = ssa_slice_len(proc, slice); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); - ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len); + ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len); ssaValue *v = ssa_emit_ptr_offset(proc, elem, index); return ssa_make_addr(v, expr); @@ -1129,31 +1069,26 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case Type_Basic: { // Basic_string TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr)); - ssaValue *elem = NULL; - ssaValue *len = NULL; - if (tv != NULL && tv->mode == Addressing_Constant) { - ssaValue *array = ssa_add_global_string_array(proc->module, tv->value.value_string); - elem = ssa_array_elem(proc, array); - len = ssa_make_const_int(a, tv->value.value_string.len); + ssaValue *str; + ssaValue *elem; + ssaValue *len; + ssaValue *index; + + if (using_addr != NULL) { + str = ssa_emit_load(proc, using_addr); } else { - ssaValue *str = NULL; - if (using_addr != NULL) { - str = ssa_emit_load(proc, using_addr); - } else { - str = ssa_build_expr(proc, ie->expr); - if (deref) { - str = ssa_emit_load(proc, str); - } + str = ssa_build_expr(proc, ie->expr); + if (deref) { + str = ssa_emit_load(proc, str); } - elem = ssa_string_elem(proc, str); - len = ssa_string_len(proc, str); } + elem = ssa_string_elem(proc, str); + len = ssa_string_len(proc, str); - ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); - ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len); + index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); + ssa_emit_bounds_check(proc, ast_node_token(ie->index), index, len); - ssaValue *v = ssa_emit_ptr_offset(proc, elem, index); - return ssa_make_addr(v, expr); + return ssa_make_addr(ssa_emit_ptr_offset(proc, elem, index), expr); } break; } case_end; @@ -1188,7 +1123,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { if (max == NULL) max = ssa_slice_cap(proc, base); GB_ASSERT(max != NULL); - ssa_slice_bounds_check(proc, se->open, low, high, max, false); + ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false); ssaValue *elem = ssa_slice_elem(proc, base); ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int); @@ -1212,7 +1147,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { if (max == NULL) max = ssa_array_cap(proc, base); GB_ASSERT(max != NULL); - ssa_slice_bounds_check(proc, se->open, low, high, max, false); + ssa_emit_slice_bounds_check(proc, se->open, low, high, max, false); ssaValue *elem = ssa_array_elem(proc, addr); ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int); @@ -1235,7 +1170,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { high = ssa_string_len(proc, base); } - ssa_slice_bounds_check(proc, se->open, low, high, high, true); + ssa_emit_slice_bounds_check(proc, se->open, low, high, high, true); ssaValue *elem, *len; len = ssa_emit_arith(proc, Token_Sub, high, low, t_int); @@ -1258,7 +1193,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(de, DerefExpr, expr); // TODO(bill): Is a ptr copy needed? - ssaValue *addr = ssa_emit_ptr_offset(proc, ssa_build_expr(proc, de->expr), v_zero); + ssaValue *addr = ssa_build_expr(proc, de->expr); + addr = ssa_emit_ptr_offset(proc, addr, v_zero); return ssa_make_addr(addr, expr); case_end; @@ -1268,15 +1204,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { Type *t = default_type(type_of_expr(proc->module->info, expr)); GB_ASSERT(is_type_tuple(t)); - Type *elem = ssa_type(maybe); - GB_ASSERT(is_type_maybe(elem)); - elem = base_type(elem)->Maybe.elem; - ssaValue *result = ssa_add_local_generated(proc, t); - ssaValue *gep0 = ssa_emit_struct_ep(proc, result, 0); - ssaValue *gep1 = ssa_emit_struct_ep(proc, result, 1); - ssa_emit_store(proc, gep0, ssa_emit_struct_ev(proc, maybe, 0)); - ssa_emit_store(proc, gep1, ssa_emit_struct_ev(proc, maybe, 1)); + ssa_emit_store(proc, result, maybe); return ssa_make_addr(result, expr); case_end; diff --git a/src/ssa/codegen.cpp b/src/ssa/codegen.cpp index b37c6b1e2..fbf9bb0c8 100644 --- a/src/ssa/codegen.cpp +++ b/src/ssa/codegen.cpp @@ -149,9 +149,9 @@ void ssa_gen_tree(ssaGen *s) { if (tav != NULL) { if (tav->value.kind != ExactValue_Invalid) { ExactValue v = tav->value; - if (v.kind != ExactValue_String) { + // if (v.kind != ExactValue_String) { g->Global.value = ssa_add_module_constant(m, tav->type, v); - } + // } } } } @@ -293,7 +293,9 @@ void ssa_gen_tree(ssaGen *s) { Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string)); auto get_type_info_ptr = [](ssaProcedure *proc, ssaValue *type_info_data, Type *type) -> ssaValue * { - return ssa_emit_array_ep(proc, type_info_data, cast(i32)ssa_type_info_index(proc->module->info, type)); + i32 index = cast(i32)ssa_type_info_index(proc->module->info, type); + // gb_printf_err("%d %s\n", index, type_to_string(type)); + return ssa_emit_array_ep(proc, type_info_data, index); }; i32 type_info_member_index = 0; @@ -319,16 +321,11 @@ void ssa_gen_tree(ssaGen *s) { tag = ssa_add_local_generated(proc, t_type_info_named); // TODO(bill): Which is better? The mangled name or actual name? - // ssaValue *gsa = ssa_add_global_string_array(proc, make_exact_value_string(t->Named.name)); - ssaValue *gsa = ssa_add_global_string_array(m, t->Named.type_name->token.string); - ssaValue *elem = ssa_array_elem(proc, gsa); - ssaValue *len = ssa_array_len(proc, ssa_emit_load(proc, gsa)); - ssaValue *name = ssa_emit_string(proc, elem, len); - - ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Named.base); + ssaValue *name = ssa_make_const_string(a, t->Named.type_name->token.string); + ssaValue *gtip = get_type_info_ptr(proc, type_info_data, t->Named.base); ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), name); - ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), gep); + ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), gtip); } break; case Type_Basic: @@ -453,7 +450,7 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *offset = ssa_emit_struct_ep(proc, field, 2); if (f->token.string.len > 0) { - ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string)); + ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string)); } ssa_emit_store(proc, type_info, tip); ssa_emit_store(proc, offset, ssa_make_const_int(a, foffset)); @@ -502,7 +499,7 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type); if (f->token.string.len > 0) { - ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string)); + ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string)); } ssa_emit_store(proc, type_info, tip); ssa_emit_store(proc, offset, ssa_make_const_int(a, 0)); @@ -571,7 +568,7 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *name_gep = ssa_emit_struct_ep(proc, name_array, i); ssa_emit_store(proc, value_gep, ssa_make_const_i64(a, fields[i]->Constant.value.value_integer)); - ssa_emit_store(proc, name_gep, ssa_emit_global_string(proc, fields[i]->token.string)); + ssa_emit_store(proc, name_gep, ssa_make_const_string(a, fields[i]->token.string)); } ssaValue *v_count = ssa_make_const_int(a, count); @@ -617,7 +614,7 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type); if (f->token.string.len > 0) { - ssa_emit_store(proc, name, ssa_emit_global_string(proc, f->token.string)); + ssa_emit_store(proc, name, ssa_make_const_string(a, f->token.string)); } ssa_emit_store(proc, type_info, tip); } diff --git a/src/ssa/emit.cpp b/src/ssa/emit.cpp index 8354249ef..a5b4f7917 100644 --- a/src/ssa/emit.cpp +++ b/src/ssa/emit.cpp @@ -37,56 +37,6 @@ ssaValue *ssa_emit_comment(ssaProcedure *p, String text) { } -ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) { - ssaBlock *b = proc->decl_block; // all variables must be in the first block - ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized); - instr->Instr.parent = b; - array_add(&b->instrs, instr); - array_add(&b->locals, instr); - - // if (zero_initialized) { - ssa_emit_zero_init(proc, instr); - // } - - return instr; -} - -ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) { - Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name)); - if (found) { - Entity *e = *found; - ssa_emit_comment(proc, e->token.string); - return ssa_add_local(proc, e, zero_initialized); - } - return NULL; -} - -ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) { - GB_ASSERT(type != NULL); - - Scope *scope = NULL; - if (proc->curr_block) { - scope = proc->curr_block->scope; - } - Entity *e = make_entity_variable(proc->module->allocator, - scope, - empty_token, - type); - return ssa_add_local(proc, e, true); -} - -ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { - ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e); -#if 1 - ssaValue *l = ssa_add_local(proc, e); - ssa_emit_store(proc, l, v); -#else - ssa_module_add_value(proc->module, e, v); -#endif - return v; -} - - ssaValue *ssa_emit_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count) { Type *pt = base_type(ssa_type(value)); GB_ASSERT(pt->kind == Type_Proc); @@ -602,31 +552,6 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba return slice; } - -ssaValue *ssa_add_global_string_array(ssaModule *m, String string) { - gbAllocator a = m->allocator; - - isize max_len = 6+8+1; - u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); - isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index); - m->global_string_index++; - - String name = make_string(str, len-1); - Token token = {Token_String}; - token.string = name; - Type *type = make_type_array(a, t_u8, string.len); - ExactValue ev = make_exact_value_string(string); - Entity *entity = make_entity_constant(a, NULL, token, type, ev); - ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev)); - g->Global.is_private = true; - // g->Global.is_constant = true; - - ssa_module_add_value(m, entity, g); - map_set(&m->members, hash_string(name), g); - - return g; -} - ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) { ssaValue *str = ssa_add_local_generated(proc, t_string); ssaValue *str_elem = ssa_emit_struct_ep(proc, str, 0); @@ -637,14 +562,6 @@ ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) { } -ssaValue *ssa_emit_global_string(ssaProcedure *proc, String str) { - ssaValue *global_array = ssa_add_global_string_array(proc->module, str); - ssaValue *elem = ssa_array_elem(proc, global_array); - ssaValue *len = ssa_make_const_int(proc->module->allocator, str.len); - return ssa_emit_string(proc, elem, len); -} - - String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { @@ -1101,10 +1018,15 @@ ssaValue *ssa_type_info(ssaProcedure *proc, Type *type) { ssaValue **found = map_get(&proc->module->members, hash_string(make_string(SSA_TYPE_INFO_DATA_NAME))); GB_ASSERT(found != NULL); ssaValue *type_info_data = *found; - CheckerInfo *info = proc->module->info; - ssaValue *entry_index = ssa_make_const_i32(proc->module->allocator, ssa_type_info_index(info, type)); - return ssa_emit_array_ep(proc, type_info_data, entry_index); + + type = default_type(type); + + i32 entry_index = ssa_type_info_index(info, type); + + // gb_printf_err("%d %s\n", entry_index, type_to_string(type)); + + return ssa_emit_array_ep(proc, type_info_data, ssa_make_const_i32(proc->module->allocator, entry_index)); } @@ -1172,6 +1094,57 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) { } +void ssa_emit_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ssaValue *len) { + if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { + return; + } + + index = ssa_emit_conv(proc, index, t_int); + len = ssa_emit_conv(proc, len, t_int); + + ssa_emit(proc, ssa_make_instr_bounds_check(proc, token.pos, index, len)); + + // gbAllocator a = proc->module->allocator; + // ssaValue **args = gb_alloc_array(a, ssaValue *, 5); + // args[0] = ssa_emit_global_string(proc, token.pos.file); + // args[1] = ssa_make_const_int(a, token.pos.line); + // args[2] = ssa_make_const_int(a, token.pos.column); + // args[3] = ssa_emit_conv(proc, index, t_int); + // args[4] = ssa_emit_conv(proc, len, t_int); + + // ssa_emit_global_call(proc, "__bounds_check_error", args, 5); +} + +void ssa_emit_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) { + if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { + return; + } + + + low = ssa_emit_conv(proc, low, t_int); + high = ssa_emit_conv(proc, high, t_int); + max = ssa_emit_conv(proc, max, t_int); + + ssa_emit(proc, ssa_make_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring)); + + // gbAllocator a = proc->module->allocator; + // ssaValue **args = gb_alloc_array(a, ssaValue *, 6); + // args[0] = ssa_emit_global_string(proc, token.pos.file); + // args[1] = ssa_make_const_int(a, token.pos.line); + // args[2] = ssa_make_const_int(a, token.pos.column); + // args[3] = ssa_emit_conv(proc, low, t_int); + // args[4] = ssa_emit_conv(proc, high, t_int); + // args[5] = ssa_emit_conv(proc, max, t_int); + + // if (!is_substring) { + // ssa_emit_global_call(proc, "__slice_expr_error", args, 6); + // } else { + // ssa_emit_global_call(proc, "__substring_expr_error", args, 5); + // } +} + + + diff --git a/src/ssa/make.cpp b/src/ssa/make.cpp index db0f0e772..1d9a29b9f 100644 --- a/src/ssa/make.cpp +++ b/src/ssa/make.cpp @@ -1,4 +1,8 @@ void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v); +ssaValue *ssa_emit_zero_init(ssaProcedure *p, ssaValue *address); +ssaValue *ssa_emit_comment(ssaProcedure *p, String text); +ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value); +ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address); ssaValue *ssa_alloc_value(gbAllocator a, ssaValueKind kind) { @@ -255,6 +259,23 @@ ssaValue *ssa_make_instr_comment(ssaProcedure *p, String text) { return v; } +ssaValue *ssa_make_instr_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *index, ssaValue *len) { + ssaValue *v = ssa_alloc_instr(p, ssaInstr_BoundsCheck); + v->Instr.BoundsCheck.pos = pos; + v->Instr.BoundsCheck.index = index; + v->Instr.BoundsCheck.len = len; + return v; +} +ssaValue *ssa_make_instr_slice_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) { + ssaValue *v = ssa_alloc_instr(p, ssaInstr_SliceBoundsCheck); + v->Instr.SliceBoundsCheck.pos = pos; + v->Instr.SliceBoundsCheck.low = low; + v->Instr.SliceBoundsCheck.high = high; + v->Instr.SliceBoundsCheck.max = max; + v->Instr.SliceBoundsCheck.is_substring = is_substring; + return v; +} + ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) { @@ -273,6 +294,14 @@ ssaValue *ssa_make_value_constant_slice(gbAllocator a, Type *type, ssaValue *bac return v; } +ssaValue *ssa_make_value_constant_string(gbAllocator a, Type *type, String string) { + ssaValue *v = ssa_alloc_value(a, ssaValue_ConstantString); + v->ConstantString.type = type; + v->ConstantString.string = string; + return v; +} + + ssaValue *ssa_make_const_int(gbAllocator a, i64 i) { return ssa_make_value_constant(a, t_int, make_exact_value_integer(i)); } @@ -285,41 +314,10 @@ ssaValue *ssa_make_const_i64(gbAllocator a, i64 i) { ssaValue *ssa_make_const_bool(gbAllocator a, b32 b) { return ssa_make_value_constant(a, t_bool, make_exact_value_bool(b != 0)); } - -ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) { - if (is_type_slice(type)) { - ast_node(cl, CompoundLit, value.value_compound); - gbAllocator a = m->allocator; - - isize count = cl->elems.count; - if (count > 0) { - Type *elem = base_type(type)->Slice.elem; - Type *t = make_type_array(a, elem, count); - ssaValue *backing_array = ssa_add_module_constant(m, t, value); - - - isize max_len = 7+8+1; - u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); - isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index); - m->global_array_index++; - - String name = make_string(str, len-1); - - Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value); - ssaValue *g = ssa_make_value_global(a, e, backing_array); - ssa_module_add_value(m, e, g); - map_set(&m->members, hash_string(name), g); - - return ssa_make_value_constant_slice(a, type, g, count); - } else { - return ssa_make_value_constant_slice(a, type, NULL, 0); - } - } - - return ssa_make_value_constant(m->allocator, type, value); +ssaValue *ssa_make_const_string(gbAllocator a, String s) { + return ssa_make_value_constant(a, t_string, make_exact_value_string(s)); } - ssaValue *ssa_make_value_procedure(gbAllocator a, ssaModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) { ssaValue *v = ssa_alloc_value(a, ssaValue_Proc); v->Proc.module = m; @@ -390,5 +388,110 @@ ssaDefer ssa_add_defer_instr(ssaProcedure *proc, isize scope_index, ssaValue *in +ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) { + if (is_type_slice(type)) { + ast_node(cl, CompoundLit, value.value_compound); + gbAllocator a = m->allocator; + + isize count = cl->elems.count; + if (count == 0) { + return ssa_make_value_nil(a, type); + } + Type *elem = base_type(type)->Slice.elem; + Type *t = make_type_array(a, elem, count); + ssaValue *backing_array = ssa_add_module_constant(m, t, value); + isize max_len = 7+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index); + m->global_array_index++; + + String name = make_string(str, len-1); + + Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value); + ssaValue *g = ssa_make_value_global(a, e, backing_array); + ssa_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); + + return ssa_make_value_constant_slice(a, type, g, count); + } + + return ssa_make_value_constant(m->allocator, type, value); +} + +ssaValue *ssa_add_global_string_array(ssaModule *m, String string) { + gbAllocator a = m->allocator; + + isize max_len = 6+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index); + m->global_string_index++; + + String name = make_string(str, len-1); + Token token = {Token_String}; + token.string = name; + Type *type = make_type_array(a, t_u8, string.len); + ExactValue ev = make_exact_value_string(string); + Entity *entity = make_entity_constant(a, NULL, token, type, ev); + ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev)); + g->Global.is_private = true; + // g->Global.is_constant = true; + + ssa_module_add_value(m, entity, g); + map_set(&m->members, hash_string(name), g); + + return g; +} + + + + +ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) { + ssaBlock *b = proc->decl_block; // all variables must be in the first block + ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized); + instr->Instr.parent = b; + array_add(&b->instrs, instr); + array_add(&b->locals, instr); + + // if (zero_initialized) { + ssa_emit_zero_init(proc, instr); + // } + + return instr; +} + +ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) { + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name)); + if (found) { + Entity *e = *found; + ssa_emit_comment(proc, e->token.string); + return ssa_add_local(proc, e, zero_initialized); + } + return NULL; +} + +ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) { + GB_ASSERT(type != NULL); + + Scope *scope = NULL; + if (proc->curr_block) { + scope = proc->curr_block->scope; + } + Entity *e = make_entity_variable(proc->module->allocator, + scope, + empty_token, + type); + return ssa_add_local(proc, e, true); +} + +ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { + ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e); +#if 1 + ssaValue *l = ssa_add_local(proc, e); + ssa_emit_store(proc, l, v); +#else + ssa_module_add_value(proc->module, e, v); +#endif + return v; +} diff --git a/src/ssa/ssa.cpp b/src/ssa/ssa.cpp index c6bb2e1cb..8f6e68af8 100644 --- a/src/ssa/ssa.cpp +++ b/src/ssa/ssa.cpp @@ -169,7 +169,9 @@ struct ssaProcedure { SSA_INSTR_KIND(VectorExtractElement), \ SSA_INSTR_KIND(VectorInsertElement), \ SSA_INSTR_KIND(VectorShuffle), \ - SSA_INSTR_KIND(StartupRuntime), + SSA_INSTR_KIND(StartupRuntime), \ + SSA_INSTR_KIND(BoundsCheck), \ + SSA_INSTR_KIND(SliceBoundsCheck), \ #define SSA_CONV_KINDS \ SSA_CONV_KIND(Invalid), \ @@ -319,6 +321,18 @@ struct ssaInstr { } VectorShuffle; struct {} StartupRuntime; + struct { + TokenPos pos; + ssaValue *index; + ssaValue *len; + } BoundsCheck; + struct { + TokenPos pos; + ssaValue *low; + ssaValue *high; + ssaValue *max; + b32 is_substring; + } SliceBoundsCheck; }; }; @@ -328,6 +342,7 @@ enum ssaValueKind { ssaValue_Constant, ssaValue_ConstantSlice, + ssaValue_ConstantString, ssaValue_Nil, ssaValue_TypeName, ssaValue_Global, @@ -349,10 +364,14 @@ struct ssaValue { ExactValue value; } Constant; struct { - Type *type; + Type * type; ssaValue *backing_array; - i64 count; + i64 count; } ConstantSlice; + struct { + Type * type; + String string; + } ConstantString; struct { Type *type; } Nil; @@ -361,18 +380,18 @@ struct ssaValue { Type * type; } TypeName; struct { - b32 is_constant; - b32 is_private; - b32 is_thread_local; - Entity * entity; - Type * type; - ssaValue *value; + b32 is_constant; + b32 is_private; + b32 is_thread_local; + Entity * entity; + Type * type; + ssaValue * value; Array referrers; } Global; struct { - ssaProcedure *parent; - Entity *entity; - Type * type; + ssaProcedure * parent; + Entity * entity; + Type * type; Array referrers; } Param; ssaProcedure Proc; @@ -523,6 +542,8 @@ Type *ssa_type(ssaValue *value) { return value->Constant.type; case ssaValue_ConstantSlice: return value->ConstantSlice.type; + case ssaValue_ConstantString: + return value->ConstantString.type; case ssaValue_Nil: return value->Nil.type; case ssaValue_TypeName: