aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-06-15 12:14:56 +0100
committerGinger Bill <bill@gingerbill.org>2017-06-15 12:14:56 +0100
commit23f9f9064e99e559f57b35a5f84a9525f8023bd9 (patch)
tree6884a9ed6133485f38d78d0d3c3c359e6a5118cc /src/ir.cpp
parenta134307dcde9aac03323c15f8dfc5642f438fe56 (diff)
Add CheckerInfo API functions
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp1458
1 files changed, 714 insertions, 744 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 8fb3be9a7..5daa42ad8 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1137,9 +1137,8 @@ irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) {
Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
if (found) {
scope = *found;
- } else {
- GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind]));
}
+ GB_ASSERT_MSG(scope != NULL, "Block scope not found for %.*s", LIT(ast_node_strings[node->kind]));
}
irValue *v = ir_alloc_value(proc->module->allocator, irValue_Block);
@@ -1290,9 +1289,8 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) {
}
irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero_initialized) {
- Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name));
- if (found) {
- Entity *e = *found;
+ Entity *e = entity_of_ident(proc->module->info, name);
+ if (e != NULL) {
ir_emit_comment(proc, e->token.string);
return ir_add_local(proc, e, name);
}
@@ -3431,7 +3429,7 @@ String ir_mangle_name(irGen *s, String path, Entity *e) {
irModule *m = &s->module;
CheckerInfo *info = m->info;
gbAllocator a = m->allocator;
- AstFile *file = *map_get(&info->files, hash_string(path));
+ AstFile *file = ast_file_of_filename(info, path);
char *str = gb_alloc_array(a, char, path.len+1);
gb_memmove(str, path.text, path.len);
@@ -3500,9 +3498,7 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) {
irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) {
GB_ASSERT(ident->kind == AstNode_Ident);
- Entity **found = map_get(&proc->module->info->uses, hash_pointer(ident));
- GB_ASSERT(found != NULL);
- Entity *e = *found;
+ Entity *e = entity_of_ident(proc->module->info, ident);
GB_ASSERT(e->kind == Entity_Label);
for_array(i, proc->branch_blocks) {
irBranchBlocks *b = &proc->branch_blocks[i];
@@ -3618,6 +3614,703 @@ bool is_double_pointer(Type *t) {
return is_type_pointer(td);
}
+irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv, Entity *e) {
+ ast_node(ce, CallExpr, expr);
+
+ switch (e->Builtin.id) {
+ case BuiltinProc_type_info: {
+ Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
+ return ir_type_info(proc, t);
+ } break;
+ case BuiltinProc_type_info_of_val: {
+ Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
+ return ir_type_info(proc, t);
+ } break;
+
+ case BuiltinProc_transmute: {
+ irValue *x = ir_build_expr(proc, ce->args[1]);
+ return ir_emit_transmute(proc, x, tv.type);
+ }
+
+ case BuiltinProc_len: {
+ irValue *v = ir_build_expr(proc, ce->args[0]);
+ Type *t = base_type(ir_type(v));
+ if (is_type_pointer(t)) {
+ // IMPORTANT TODO(bill): Should there be a nil pointer check?
+ v = ir_emit_load(proc, v);
+ t = type_deref(t);
+ }
+ if (is_type_string(t)) {
+ return ir_string_len(proc, v);
+ } else if (is_type_array(t)) {
+ GB_PANIC("Array lengths are constant");
+ } else if (is_type_vector(t)) {
+ GB_PANIC("Vector lengths are constant");
+ } else if (is_type_slice(t)) {
+ return ir_slice_count(proc, v);
+ } else if (is_type_dynamic_array(t)) {
+ return ir_dynamic_array_count(proc, v);
+ } else if (is_type_dynamic_map(t)) {
+ ir_emit_comment(proc, str_lit("len: map"));
+ irValue *entries = ir_emit_struct_ev(proc, v, 1);
+ return ir_dynamic_array_count(proc, entries);
+ }
+
+ GB_PANIC("Unreachable");
+ } break;
+
+ case BuiltinProc_cap: {
+ irValue *v = ir_build_expr(proc, ce->args[0]);
+ Type *t = base_type(ir_type(v));
+ if (is_type_pointer(t)) {
+ // IMPORTANT TODO(bill): Should there be a nil pointer check?
+ v = ir_emit_load(proc, v);
+ t = type_deref(t);
+ }
+ if (is_type_string(t)) {
+ GB_PANIC("Unreachable");
+ } else if (is_type_array(t)) {
+ GB_PANIC("Array lengths are constant");
+ } else if (is_type_vector(t)) {
+ GB_PANIC("Unreachable");
+ } else if (is_type_slice(t)) {
+ return ir_slice_capacity(proc, v);
+ } else if (is_type_dynamic_array(t)) {
+ return ir_dynamic_array_capacity(proc, v);
+ } else if (is_type_map(t)) {
+ irValue *entries = ir_emit_struct_ev(proc, v, 1);
+ return ir_dynamic_array_capacity(proc, entries);
+ }
+
+ GB_PANIC("Unreachable");
+
+ } break;
+
+ case BuiltinProc_new: {
+ ir_emit_comment(proc, str_lit("new"));
+ // new :: proc(Type) -> ^Type
+ gbAllocator a = proc->module->allocator;
+
+ Type *type = type_of_expr(proc->module->info, ce->args[0]);
+ Type *allocation_type = type;
+ i32 variant_index = 0;
+ if (is_type_struct(type)) {
+ Type *st = base_type(type);
+ if (st->Record.variant_parent != NULL) {
+ allocation_type = st->Record.variant_parent;
+ variant_index = st->Record.variant_index;
+ GB_ASSERT(allocation_type != NULL);
+ }
+ }
+ Type *ptr_type = make_type_pointer(a, type);
+
+ i64 size = type_size_of(a, allocation_type);
+ i64 align = type_align_of(a, allocation_type);
+
+ irValue **args = gb_alloc_array(a, irValue *, 2);
+ args[0] = ir_const_int(a, size);
+ args[1] = ir_const_int(a, align);
+ irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
+ irValue *v = ir_emit_conv(proc, call, ptr_type);
+ if (type != allocation_type) {
+ Type *u = base_type(allocation_type);
+ Type *uptr_type = make_type_pointer(a, u);
+ irValue *parent = ir_emit_conv(proc, call, uptr_type);
+ irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
+ ir_emit_store(proc, tag_ptr, ir_const_int(a, variant_index));
+ }
+ return v;
+ } break;
+
+ case BuiltinProc_make: {
+ ir_emit_comment(proc, str_lit("make"));
+ gbAllocator a = proc->module->allocator;
+ Type *type = type_of_expr(proc->module->info, ce->args[0]);
+
+ if (is_type_slice(type)) {
+ Type *elem_type = core_type(type)->Slice.elem;
+ Type *elem_ptr_type = make_type_pointer(a, elem_type);
+
+ irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type));
+ irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type));
+
+ irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
+ irValue *capacity = count;
+
+ if (ce->args.count == 3) {
+ capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int);
+ }
+
+ ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, count, capacity, false);
+
+ irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int);
+
+ irValue **args = gb_alloc_array(a, irValue *, 2);
+ args[0] = slice_size;
+ args[1] = elem_align;
+ irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
+
+ irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type);
+ irValue *slice = ir_add_local_generated(proc, type);
+
+ ir_fill_slice(proc, slice, ptr, count, capacity);
+ return ir_emit_load(proc, slice);
+ } else if (is_type_dynamic_map(type)) {
+ irValue *int_16 = ir_const_int(a, 16);
+ irValue *cap = int_16;
+ if (ce->args.count == 2) {
+ cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
+ }
+
+ irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero);
+ cap = ir_emit_select(proc, cond, cap, int_16);
+
+ irValue *map = ir_add_local_generated(proc, type);
+ irValue *header = ir_gen_map_header(proc, map, base_type(type));
+ irValue **args = gb_alloc_array(a, irValue *, 2);
+ args[0] = header;
+ args[1] = cap;
+ ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
+
+ return ir_emit_load(proc, map);
+ } else if (is_type_dynamic_array(type)) {
+ Type *elem_type = base_type(type)->DynamicArray.elem;
+ irValue *len = v_zero;
+ if (ce->args.count > 1) {
+ len = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
+ }
+ irValue *cap = len;
+ if (ce->args.count > 2) {
+ cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int);
+ }
+
+ ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false);
+
+ irValue *array = ir_add_local_generated(proc, type);
+ irValue **args = gb_alloc_array(a, irValue *, 5);
+ args[0] = ir_emit_conv(proc, array, t_rawptr);
+ args[1] = ir_const_int(a, type_size_of(a, elem_type));
+ args[2] = ir_const_int(a, type_align_of(a, elem_type));;
+ args[3] = len;
+ args[4] = cap;
+ ir_emit_global_call(proc, "__dynamic_array_make", args, 5);
+
+ return ir_emit_load(proc, array);
+ }
+ } break;
+
+ case BuiltinProc_free: {
+ ir_emit_comment(proc, str_lit("free"));
+
+ gbAllocator a = proc->module->allocator;
+
+ AstNode *node = ce->args[0];
+ TypeAndValue tav = type_and_value_of_expr(proc->module->info, node);
+ Type *type = base_type(tav.type);
+
+ if (is_type_dynamic_array(type)) {
+ irValue *val = ir_build_expr(proc, node);
+ irValue *da_allocator = ir_emit_struct_ev(proc, val, 3);
+
+ irValue *ptr = ir_emit_struct_ev(proc, val, 0);
+ ptr = ir_emit_conv(proc, ptr, t_rawptr);
+
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = da_allocator;
+ args[1] = ptr;
+ return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
+ } else if (is_type_dynamic_map(type)) {
+ irValue *map = ir_build_expr(proc, node);
+ irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map);
+
+ {
+ irValue *array = ir_emit_struct_ep(proc, map_ptr, 0);
+
+ irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
+ irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
+ da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
+
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = da_allocator;
+ args[1] = da_ptr;
+ ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
+ }
+ {
+ irValue *array = ir_emit_struct_ep(proc, map_ptr, 1);
+
+ irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
+ irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
+ da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
+
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = da_allocator;
+ args[1] = da_ptr;
+ ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
+ }
+ return NULL;
+ }
+
+ irValue *val = ir_build_expr(proc, node);
+ irValue *ptr = NULL;
+ if (is_type_pointer(type)) {
+ ptr = val;
+ } else if (is_type_slice(type)) {
+ ptr = ir_slice_elem(proc, val);
+ } else if (is_type_string(type)) {
+ ptr = ir_string_elem(proc, val);
+ } else {
+ GB_PANIC("Invalid type to `free`");
+ }
+
+ if (ptr == NULL) {
+ return NULL;
+ }
+
+ ptr = ir_emit_conv(proc, ptr, t_rawptr);
+
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = ptr;
+ return ir_emit_global_call(proc, "free_ptr", args, 1);
+ } break;
+
+ case BuiltinProc_reserve: {
+ ir_emit_comment(proc, str_lit("reserve"));
+ gbAllocator a = proc->module->allocator;
+
+ irValue *ptr = ir_build_addr(proc, ce->args[0]).addr;
+ Type *type = ir_type(ptr);
+ GB_ASSERT(is_type_pointer(type));
+ type = base_type(type_deref(type));
+
+ irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
+
+ if (is_type_dynamic_array(type)) {
+ Type *elem = type->DynamicArray.elem;
+
+ irValue *elem_size = ir_const_int(a, type_size_of(a, elem));
+ irValue *elem_align = ir_const_int(a, type_align_of(a, elem));
+
+ ptr = ir_emit_conv(proc, ptr, t_rawptr);
+
+ irValue **args = gb_alloc_array(a, irValue *, 4);
+ args[0] = ptr;
+ args[1] = elem_size;
+ args[2] = elem_align;
+ args[3] = capacity;
+ return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
+ } else if (is_type_dynamic_map(type)) {
+ irValue **args = gb_alloc_array(a, irValue *, 2);
+ args[0] = ir_gen_map_header(proc, ptr, type);
+ args[1] = capacity;
+ return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
+ } else {
+ GB_PANIC("Unknown type for `reserve`");
+ }
+ } break;
+
+ case BuiltinProc_clear: {
+ ir_emit_comment(proc, str_lit("clear"));
+ Type *original_type = type_of_expr(proc->module->info, ce->args[0]);
+ irAddr addr = ir_build_addr(proc, ce->args[0]);
+ irValue *ptr = addr.addr;
+ if (is_double_pointer(ir_type(ptr))) {
+ ptr = ir_addr_load(proc, addr);
+ }
+ Type *t = base_type(type_deref(original_type));
+ if (is_type_dynamic_array(t)) {
+ irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
+ ir_emit_store(proc, count_ptr, v_zero);
+ } else if (is_type_dynamic_map(t)) {
+ irValue *ha = ir_emit_struct_ep(proc, ptr, 0);
+ irValue *ea = ir_emit_struct_ep(proc, ptr, 1);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero);
+ } else if (is_type_slice(t)) {
+ irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
+ ir_emit_store(proc, count_ptr, v_zero);
+ } else {
+ GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t));
+ }
+ return NULL;
+ } break;
+
+ case BuiltinProc_append: {
+ ir_emit_comment(proc, str_lit("append"));
+ gbAllocator a = proc->module->allocator;
+
+ Type *value_type = type_of_expr(proc->module->info, ce->args[0]);
+ irAddr array_addr = ir_build_addr(proc, ce->args[0]);
+ irValue *array_ptr = array_addr.addr;
+ if (is_double_pointer(ir_type(array_ptr))) {
+ array_ptr = ir_addr_load(proc, array_addr);
+ }
+ Type *type = ir_type(array_ptr);
+ {
+ TokenPos pos = ast_node_token(ce->args[0]).pos;
+ GB_ASSERT_MSG(is_type_pointer(type), "%.*s(%td) %s",
+ LIT(pos.file), pos.line,
+ type_to_string(type));
+ }
+ type = base_type(type_deref(type));
+ Type *elem_type = NULL;
+ bool is_slice = false;
+ if (is_type_dynamic_array(type)) {
+ elem_type = type->DynamicArray.elem;
+ } else if (is_type_slice(type)) {
+ is_slice = true;
+ elem_type = type->Slice.elem;
+ } else {
+ GB_PANIC("Invalid type to append");
+ }
+
+ irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type));
+ irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type));
+
+ array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
+
+ isize arg_index = 0;
+ isize arg_count = 0;
+ for_array(i, ce->args) {
+ AstNode *a = ce->args[i];
+ Type *at = base_type(type_of_expr(proc->module->info, a));
+ if (at->kind == Type_Tuple) {
+ arg_count += at->Tuple.variable_count;
+ } else {
+ arg_count++;
+ }
+ }
+
+ irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count);
+ bool vari_expand = ce->ellipsis.pos.line != 0;
+
+ for_array(i, ce->args) {
+ irValue *a = ir_build_expr(proc, ce->args[i]);
+ Type *at = ir_type(a);
+ if (at->kind == Type_Tuple) {
+ for (isize i = 0; i < at->Tuple.variable_count; i++) {
+ Entity *e = at->Tuple.variables[i];
+ irValue *v = ir_emit_struct_ev(proc, a, i);
+ args[arg_index++] = v;
+ }
+ } else {
+ args[arg_index++] = a;
+ }
+ }
+
+ if (!vari_expand) {
+ for (isize i = 1; i < arg_count; i++) {
+ args[i] = ir_emit_conv(proc, args[i], elem_type);
+ }
+ }
+
+ if (!vari_expand) {
+ ir_emit_comment(proc, str_lit("variadic call argument generation"));
+ Type *slice_type = make_type_slice(a, elem_type);
+ irValue *slice = ir_add_local_generated(proc, slice_type);
+ isize slice_len = arg_count-1;
+
+ if (slice_len > 0) {
+ irValue *base_array = ir_add_local_generated(proc, make_type_array(a, elem_type, slice_len));
+
+ for (isize i = 1; i < arg_count; i++) {
+ irValue *addr = ir_emit_array_epi(proc, base_array, i-1);
+ ir_emit_store(proc, addr, args[i]);
+ }
+
+ irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
+ irValue *len = ir_const_int(a, slice_len);
+ ir_fill_slice(proc, slice, base_elem, len, len);
+ }
+
+ arg_count = 2;
+ args[arg_count-1] = ir_emit_load(proc, slice);
+ }
+
+ irValue *item_slice = args[1];
+ irValue *items = ir_slice_elem(proc, item_slice);
+ irValue *item_count = ir_slice_count(proc, item_slice);
+
+ irValue **daa_args = gb_alloc_array(a, irValue *, 5);
+ daa_args[0] = array_ptr;
+ daa_args[1] = elem_size;
+ daa_args[2] = elem_align;
+ daa_args[3] = ir_emit_conv(proc, items, t_rawptr);
+ daa_args[4] = ir_emit_conv(proc, item_count, t_int);
+
+ if (is_slice) {
+ return ir_emit_global_call(proc, "__slice_append", daa_args, 5);
+ }
+ return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
+ } break;
+
+ case BuiltinProc_delete: {
+ ir_emit_comment(proc, str_lit("delete"));
+ irValue *map = ir_build_expr(proc, ce->args[0]);
+ irValue *key = ir_build_expr(proc, ce->args[1]);
+ Type *map_type = ir_type(map);
+ GB_ASSERT(is_type_dynamic_map(map_type));
+ Type *key_type = base_type(map_type)->Map.key;
+
+ irValue *addr = ir_address_from_load_or_generate_local(proc, map);
+
+ gbAllocator a = proc->module->allocator;
+ irValue **args = gb_alloc_array(a, irValue *, 2);
+ args[0] = ir_gen_map_header(proc, addr, map_type);
+ args[1] = ir_gen_map_key(proc, key, key_type);
+ return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2);
+ } break;
+
+
+ case BuiltinProc_assert: {
+ ir_emit_comment(proc, str_lit("assert"));
+ irValue *cond = ir_build_expr(proc, ce->args[0]);
+ GB_ASSERT(is_type_boolean(ir_type(cond)));
+
+ cond = ir_emit_comp(proc, Token_CmpEq, cond, v_false);
+ irBlock *err = ir_new_block(proc, NULL, "builtin.assert.err");
+ irBlock *done = ir_new_block(proc, NULL, "builtin.assert.done");
+
+ ir_emit_if(proc, cond, err, done);
+ ir_start_block(proc, err);
+
+ // TODO(bill): Cleanup allocations here
+ Token token = ast_node_token(ce->args[0]);
+ TokenPos pos = token.pos;
+ gbString expr = expr_to_string(ce->args[0]);
+ isize expr_len = gb_string_length(expr);
+ String expr_str = {};
+ expr_str.text = cast(u8 *)gb_alloc_copy_align(proc->module->allocator, expr, expr_len, 1);
+ expr_str.len = expr_len;
+ gb_string_free(expr);
+
+
+ irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
+ args[0] = ir_const_string(proc->module->allocator, pos.file);
+ args[1] = ir_const_int(proc->module->allocator, pos.line);
+ args[2] = ir_const_int(proc->module->allocator, pos.column);
+ args[3] = ir_const_string(proc->module->allocator, expr_str);
+ ir_emit_global_call(proc, "__assert", args, 4);
+
+ ir_emit_jump(proc, done);
+ ir_start_block(proc, done);
+
+ return cond;
+ } break;
+
+ case BuiltinProc_panic: {
+ ir_emit_comment(proc, str_lit("panic"));
+ irValue *msg = ir_build_expr(proc, ce->args[0]);
+ GB_ASSERT(is_type_string(ir_type(msg)));
+
+ Token token = ast_node_token(ce->args[0]);
+ TokenPos pos = token.pos;
+
+ irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
+ args[0] = ir_const_string(proc->module->allocator, pos.file);
+ args[1] = ir_const_int(proc->module->allocator, pos.line);
+ args[2] = ir_const_int(proc->module->allocator, pos.column);
+ args[3] = msg;
+ ir_emit_global_call(proc, "__panic", args, 4);
+
+ return NULL;
+ } break;
+
+
+ case BuiltinProc_copy: {
+ ir_emit_comment(proc, str_lit("copy"));
+ // copy :: proc(dst, src: []Type) -> int
+ AstNode *dst_node = ce->args[0];
+ AstNode *src_node = ce->args[1];
+ irValue *dst_slice = ir_build_expr(proc, dst_node);
+ irValue *src_slice = ir_build_expr(proc, src_node);
+ Type *slice_type = base_type(ir_type(dst_slice));
+ GB_ASSERT(slice_type->kind == Type_Slice);
+ Type *elem_type = slice_type->Slice.elem;
+ i64 size_of_elem = type_size_of(proc->module->allocator, elem_type);
+
+ irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr);
+ irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr);
+
+ irValue *len_dst = ir_slice_count(proc, dst_slice);
+ irValue *len_src = ir_slice_count(proc, src_slice);
+
+ irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src);
+ irValue *len = ir_emit_select(proc, cond, len_dst, len_src);
+
+ irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem);
+ irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int);
+
+ irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
+ args[0] = dst;
+ args[1] = src;
+ args[2] = byte_count;
+
+ ir_emit_global_call(proc, "__mem_copy", args, 3);
+
+ return len;
+ } break;
+ case BuiltinProc_swizzle: {
+ ir_emit_comment(proc, str_lit("swizzle.begin"));
+ irAddr vector_addr = ir_build_addr(proc, ce->args[0]);
+ isize index_count = ce->args.count-1;
+ if (index_count == 0) {
+ return ir_addr_load(proc, vector_addr);
+ }
+ irValue *src = vector_addr.addr;
+ irValue *dst = ir_add_local_generated(proc, tv.type);
+
+ for (i32 i = 1; i < ce->args.count; i++) {
+ TypeAndValue tv = type_and_value_of_expr(proc->module->info, ce->args[i]);
+ GB_ASSERT(is_type_integer(tv.type));
+ GB_ASSERT(tv.value.kind == ExactValue_Integer);
+
+ i32 src_index = cast(i32)i128_to_i64(tv.value.value_integer);
+ i32 dst_index = i-1;
+
+ irValue *src_elem = ir_emit_array_epi(proc, src, src_index);
+ irValue *dst_elem = ir_emit_array_epi(proc, dst, dst_index);
+
+ ir_emit_store(proc, dst_elem, ir_emit_load(proc, src_elem));
+ }
+ ir_emit_comment(proc, str_lit("swizzle.end"));
+ return ir_emit_load(proc, dst);
+ // return ir_emit(proc, ir_instr_vector_shuffle(proc, vector, indices, index_count));
+ } break;
+
+ case BuiltinProc_complex: {
+ ir_emit_comment(proc, str_lit("complex"));
+ irValue *real = ir_build_expr(proc, ce->args[0]);
+ irValue *imag = ir_build_expr(proc, ce->args[1]);
+ irValue *dst = ir_add_local_generated(proc, tv.type);
+
+ Type *ft = base_complex_elem_type(tv.type);
+ real = ir_emit_conv(proc, real, ft);
+ imag = ir_emit_conv(proc, imag, ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), imag);
+
+ return ir_emit_load(proc, dst);
+ } break;
+
+ case BuiltinProc_real: {
+ ir_emit_comment(proc, str_lit("real"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ irValue *real = ir_emit_struct_ev(proc, val, 0);
+ return ir_emit_conv(proc, real, tv.type);
+ } break;
+ case BuiltinProc_imag: {
+ ir_emit_comment(proc, str_lit("imag"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ return ir_emit_conv(proc, imag, tv.type);
+ } break;
+
+ case BuiltinProc_conj: {
+ ir_emit_comment(proc, str_lit("conj"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ irValue *res = NULL;
+ Type *t = ir_type(val);
+ if (is_type_complex(t)) {
+ res = ir_add_local_generated(proc, tv.type);
+ irValue *real = ir_emit_struct_ev(proc, val, 0);
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag);
+ }
+ return ir_emit_load(proc, res);
+ } break;
+
+ case BuiltinProc_slice_ptr: {
+ ir_emit_comment(proc, str_lit("slice_ptr"));
+ irValue *ptr = ir_build_expr(proc, ce->args[0]);
+ irValue *count = ir_build_expr(proc, ce->args[1]);
+ count = ir_emit_conv(proc, count, t_int);
+ irValue *capacity = count;
+ if (ce->args.count > 2) {
+ capacity = ir_build_expr(proc, ce->args[2]);
+ capacity = ir_emit_conv(proc, capacity, t_int);
+ }
+
+ Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr)));
+ irValue *slice = ir_add_local_generated(proc, slice_type);
+ ir_fill_slice(proc, slice, ptr, count, capacity);
+ return ir_emit_load(proc, slice);
+ } break;
+
+ case BuiltinProc_slice_to_bytes: {
+ ir_emit_comment(proc, str_lit("slice_to_bytes"));
+ irValue *s = ir_build_expr(proc, ce->args[0]);
+ Type *t = base_type(ir_type(s));
+ if (is_type_u8_slice(t)) {
+ return ir_emit_conv(proc, s, tv.type);
+ }
+ irValue *slice = ir_add_local_generated(proc, tv.type);
+ i64 elem_size = type_size_of(proc->module->allocator, t->Slice.elem);
+
+ irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
+ irValue *count = ir_slice_count(proc, s);
+ irValue *capacity = ir_slice_capacity(proc, s);
+ count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int);
+ capacity = ir_emit_arith(proc, Token_Mul, capacity, ir_const_int(proc->module->allocator, elem_size), t_int);
+ ir_fill_slice(proc, slice, ptr, count, capacity);
+ return ir_emit_load(proc, slice);
+ } break;
+
+ case BuiltinProc_min: {
+ ir_emit_comment(proc, str_lit("min"));
+ Type *t = type_of_expr(proc->module->info, expr);
+ irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t);
+ irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t);
+ irValue *cond = ir_emit_comp(proc, Token_Lt, x, y);
+ return ir_emit_select(proc, cond, x, y);
+ } break;
+
+ case BuiltinProc_max: {
+ ir_emit_comment(proc, str_lit("max"));
+ Type *t = type_of_expr(proc->module->info, expr);
+ irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t);
+ irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t);
+ irValue *cond = ir_emit_comp(proc, Token_Gt, x, y);
+ return ir_emit_select(proc, cond, x, y);
+ } break;
+
+ case BuiltinProc_abs: {
+ ir_emit_comment(proc, str_lit("abs"));
+ irValue *x = ir_build_expr(proc, ce->args[0]);
+ Type *t = ir_type(x);
+ if (is_type_complex(t)) {
+ gbAllocator a = proc->module->allocator;
+ i64 sz = 8*type_size_of(a, t);
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = x;
+ switch (sz) {
+ case 64: return ir_emit_global_call(proc, "__abs_complex64", args, 1);
+ case 128: return ir_emit_global_call(proc, "__abs_complex128", args, 1);
+ }
+ GB_PANIC("Unknown complex type");
+ }
+ irValue *zero = ir_emit_conv(proc, v_zero, t);
+ irValue *cond = ir_emit_comp(proc, Token_Lt, x, zero);
+ irValue *neg = ir_emit(proc, ir_instr_unary_op(proc, Token_Sub, x, t));
+ return ir_emit_select(proc, cond, neg, x);
+ } break;
+
+ case BuiltinProc_clamp: {
+ ir_emit_comment(proc, str_lit("clamp"));
+ Type *t = type_of_expr(proc->module->info, expr);
+ return ir_emit_clamp(proc, t,
+ ir_build_expr(proc, ce->args[0]),
+ ir_build_expr(proc, ce->args[1]),
+ ir_build_expr(proc, ce->args[2]));
+ } break;
+ }
+
+ GB_PANIC("Unhandled built-in procedure");
+ return NULL;
+}
+
+
irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
expr = unparen_expr(expr);
@@ -3657,7 +4350,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
case_end;
case_ast_node(i, Ident, expr);
- Entity *e = *map_get(&proc->module->info->uses, hash_pointer(expr));
+ Entity *e = entity_of_ident(proc->module->info, expr);
if (e->kind == Entity_Builtin) {
Token token = ast_node_token(expr);
GB_PANIC("TODO(bill): ir_build_single_expr Entity_Builtin `%.*s`\n"
@@ -3870,7 +4563,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
case_ast_node(ce, CallExpr, expr);
- if (map_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) {
+ if (type_and_value_of_expr(proc->module->info, ce->proc).mode == Addressing_Type) {
GB_ASSERT(ce->args.count == 1);
irValue *x = ir_build_expr(proc, ce->args[0]);
irValue *y = ir_emit_conv(proc, x, tv.type);
@@ -3879,720 +4572,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
AstNode *p = unparen_expr(ce->proc);
if (p->kind == AstNode_Ident) {
- Entity **found = map_get(&proc->module->info->uses, hash_pointer(p));
- if (found && (*found)->kind == Entity_Builtin) {
- Entity *e = *found;
- switch (e->Builtin.id) {
- case BuiltinProc_type_info: {
- Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
- return ir_type_info(proc, t);
- } break;
- case BuiltinProc_type_info_of_val: {
- Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
- return ir_type_info(proc, t);
- } break;
-
- case BuiltinProc_transmute: {
- irValue *x = ir_build_expr(proc, ce->args[1]);
- return ir_emit_transmute(proc, x, tv.type);
- }
-
- case BuiltinProc_len: {
- irValue *v = ir_build_expr(proc, ce->args[0]);
- Type *t = base_type(ir_type(v));
- if (is_type_pointer(t)) {
- // IMPORTANT TODO(bill): Should there be a nil pointer check?
- v = ir_emit_load(proc, v);
- t = type_deref(t);
- }
- if (is_type_string(t)) {
- return ir_string_len(proc, v);
- } else if (is_type_array(t)) {
- GB_PANIC("Array lengths are constant");
- } else if (is_type_vector(t)) {
- GB_PANIC("Vector lengths are constant");
- } else if (is_type_slice(t)) {
- return ir_slice_count(proc, v);
- } else if (is_type_dynamic_array(t)) {
- return ir_dynamic_array_count(proc, v);
- } else if (is_type_dynamic_map(t)) {
- ir_emit_comment(proc, str_lit("len: map"));
- irValue *entries = ir_emit_struct_ev(proc, v, 1);
- return ir_dynamic_array_count(proc, entries);
- }
-
- GB_PANIC("Unreachable");
- } break;
-
- case BuiltinProc_cap: {
- irValue *v = ir_build_expr(proc, ce->args[0]);
- Type *t = base_type(ir_type(v));
- if (is_type_pointer(t)) {
- // IMPORTANT TODO(bill): Should there be a nil pointer check?
- v = ir_emit_load(proc, v);
- t = type_deref(t);
- }
- if (is_type_string(t)) {
- GB_PANIC("Unreachable");
- } else if (is_type_array(t)) {
- GB_PANIC("Array lengths are constant");
- } else if (is_type_vector(t)) {
- GB_PANIC("Unreachable");
- } else if (is_type_slice(t)) {
- return ir_slice_capacity(proc, v);
- } else if (is_type_dynamic_array(t)) {
- return ir_dynamic_array_capacity(proc, v);
- } else if (is_type_map(t)) {
- irValue *entries = ir_emit_struct_ev(proc, v, 1);
- return ir_dynamic_array_capacity(proc, entries);
- }
-
- GB_PANIC("Unreachable");
-
- } break;
-
- case BuiltinProc_new: {
- ir_emit_comment(proc, str_lit("new"));
- // new :: proc(Type) -> ^Type
- gbAllocator allocator = proc->module->allocator;
-
- Type *type = type_of_expr(proc->module->info, ce->args[0]);
- Type *ptr_type = make_type_pointer(allocator, type);
-
- i64 s = type_size_of(allocator, type);
- i64 a = type_align_of(allocator, type);
-
- irValue **args = gb_alloc_array(allocator, irValue *, 2);
- args[0] = ir_const_int(allocator, s);
- args[1] = ir_const_int(allocator, a);
- irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
- irValue *v = ir_emit_conv(proc, call, ptr_type);
- return v;
- } break;
-
- #if 0
- case BuiltinProc_new_slice: {
- ir_emit_comment(proc, str_lit("new_slice"));
- // new_slice :: proc(Type, len: int) -> []Type
- // new_slice :: proc(Type, len, cap: int) -> []Type
- gbAllocator allocator = proc->module->allocator;
-
- Type *type = type_of_expr(proc->module->info, ce->args[0]);
- Type *ptr_type = make_type_pointer(allocator, type);
- Type *slice_type = make_type_slice(allocator, type);
-
- i64 s = type_size_of(allocator, type);
- i64 a = type_align_of(allocator, type);
-
- irValue *elem_size = ir_const_int(allocator, s);
- irValue *elem_align = ir_const_int(allocator, a);
-
- irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
- irValue *capacity = count;
-
- if (ce->args.count == 3) {
- capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int);
- }
-
- ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, count, capacity, false);
-
- irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int);
-
- irValue **args = gb_alloc_array(allocator, irValue *, 2);
- args[0] = slice_size;
- args[1] = elem_align;
- irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
-
- irValue *ptr = ir_emit_conv(proc, call, ptr_type);
- irValue *slice = ir_add_local_generated(proc, slice_type);
-
- ir_fill_slice(proc, slice, ptr, count, capacity);
- return ir_emit_load(proc, slice);
- } break;
- #endif
- case BuiltinProc_make: {
- ir_emit_comment(proc, str_lit("make"));
- gbAllocator a = proc->module->allocator;
- Type *type = type_of_expr(proc->module->info, ce->args[0]);
-
- if (is_type_slice(type)) {
- Type *elem_type = core_type(type)->Slice.elem;
- Type *elem_ptr_type = make_type_pointer(a, elem_type);
-
- irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type));
- irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type));
-
- irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
- irValue *capacity = count;
-
- if (ce->args.count == 3) {
- capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int);
- }
-
- ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, count, capacity, false);
-
- irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int);
-
- irValue **args = gb_alloc_array(a, irValue *, 2);
- args[0] = slice_size;
- args[1] = elem_align;
- irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
-
- irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type);
- irValue *slice = ir_add_local_generated(proc, type);
-
- ir_fill_slice(proc, slice, ptr, count, capacity);
- return ir_emit_load(proc, slice);
- } else if (is_type_dynamic_map(type)) {
- irValue *int_16 = ir_const_int(a, 16);
- irValue *cap = int_16;
- if (ce->args.count == 2) {
- cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
- }
-
- irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero);
- cap = ir_emit_select(proc, cond, cap, int_16);
-
- irValue *map = ir_add_local_generated(proc, type);
- irValue *header = ir_gen_map_header(proc, map, base_type(type));
- irValue **args = gb_alloc_array(a, irValue *, 2);
- args[0] = header;
- args[1] = cap;
- ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
-
- return ir_emit_load(proc, map);
- } else if (is_type_dynamic_array(type)) {
- Type *elem_type = base_type(type)->DynamicArray.elem;
- irValue *len = v_zero;
- if (ce->args.count > 1) {
- len = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
- }
- irValue *cap = len;
- if (ce->args.count > 2) {
- cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int);
- }
-
- ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false);
-
- irValue *array = ir_add_local_generated(proc, type);
- irValue **args = gb_alloc_array(a, irValue *, 5);
- args[0] = ir_emit_conv(proc, array, t_rawptr);
- args[1] = ir_const_int(a, type_size_of(a, elem_type));
- args[2] = ir_const_int(a, type_align_of(a, elem_type));;
- args[3] = len;
- args[4] = cap;
- ir_emit_global_call(proc, "__dynamic_array_make", args, 5);
-
- return ir_emit_load(proc, array);
- }
- } break;
-
- case BuiltinProc_free: {
- ir_emit_comment(proc, str_lit("free"));
-
- gbAllocator a = proc->module->allocator;
-
- AstNode *node = ce->args[0];
- TypeAndValue tav = type_and_value_of_expr(proc->module->info, node);
- Type *type = base_type(tav.type);
-
- if (is_type_dynamic_array(type)) {
- irValue *val = ir_build_expr(proc, node);
- irValue *da_allocator = ir_emit_struct_ev(proc, val, 3);
-
- irValue *ptr = ir_emit_struct_ev(proc, val, 0);
- ptr = ir_emit_conv(proc, ptr, t_rawptr);
-
- irValue **args = gb_alloc_array(a, irValue *, 1);
- args[0] = da_allocator;
- args[1] = ptr;
- return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
- } else if (is_type_dynamic_map(type)) {
- irValue *map = ir_build_expr(proc, node);
- irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map);
-
- {
- irValue *array = ir_emit_struct_ep(proc, map_ptr, 0);
-
- irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
- irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
- da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
-
- irValue **args = gb_alloc_array(a, irValue *, 1);
- args[0] = da_allocator;
- args[1] = da_ptr;
- ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
- }
- {
- irValue *array = ir_emit_struct_ep(proc, map_ptr, 1);
-
- irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3));
- irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0));
- da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr);
-
- irValue **args = gb_alloc_array(a, irValue *, 1);
- args[0] = da_allocator;
- args[1] = da_ptr;
- ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
- }
- return NULL;
- }
-
- irValue *val = ir_build_expr(proc, node);
- irValue *ptr = NULL;
- if (is_type_pointer(type)) {
- ptr = val;
- } else if (is_type_slice(type)) {
- ptr = ir_slice_elem(proc, val);
- } else if (is_type_string(type)) {
- ptr = ir_string_elem(proc, val);
- } else {
- GB_PANIC("Invalid type to `free`");
- }
-
- if (ptr == NULL) {
- return NULL;
- }
-
- ptr = ir_emit_conv(proc, ptr, t_rawptr);
-
- irValue **args = gb_alloc_array(a, irValue *, 1);
- args[0] = ptr;
- return ir_emit_global_call(proc, "free_ptr", args, 1);
- } break;
-
- case BuiltinProc_reserve: {
- ir_emit_comment(proc, str_lit("reserve"));
- gbAllocator a = proc->module->allocator;
-
- irValue *ptr = ir_build_addr(proc, ce->args[0]).addr;
- Type *type = ir_type(ptr);
- GB_ASSERT(is_type_pointer(type));
- type = base_type(type_deref(type));
-
- irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int);
-
- if (is_type_dynamic_array(type)) {
- Type *elem = type->DynamicArray.elem;
-
- irValue *elem_size = ir_const_int(a, type_size_of(a, elem));
- irValue *elem_align = ir_const_int(a, type_align_of(a, elem));
-
- ptr = ir_emit_conv(proc, ptr, t_rawptr);
-
- irValue **args = gb_alloc_array(a, irValue *, 4);
- args[0] = ptr;
- args[1] = elem_size;
- args[2] = elem_align;
- args[3] = capacity;
- return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
- } else if (is_type_dynamic_map(type)) {
- irValue **args = gb_alloc_array(a, irValue *, 2);
- args[0] = ir_gen_map_header(proc, ptr, type);
- args[1] = capacity;
- return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
- } else {
- GB_PANIC("Unknown type for `reserve`");
- }
- } break;
-
- case BuiltinProc_clear: {
- ir_emit_comment(proc, str_lit("clear"));
- Type *original_type = type_of_expr(proc->module->info, ce->args[0]);
- irAddr addr = ir_build_addr(proc, ce->args[0]);
- irValue *ptr = addr.addr;
- if (is_double_pointer(ir_type(ptr))) {
- ptr = ir_addr_load(proc, addr);
- }
- Type *t = base_type(type_deref(original_type));
- if (is_type_dynamic_array(t)) {
- irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
- ir_emit_store(proc, count_ptr, v_zero);
- } else if (is_type_dynamic_map(t)) {
- irValue *ha = ir_emit_struct_ep(proc, ptr, 0);
- irValue *ea = ir_emit_struct_ep(proc, ptr, 1);
- ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero);
- ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero);
- } else if (is_type_slice(t)) {
- irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
- ir_emit_store(proc, count_ptr, v_zero);
- } else {
- GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t));
- }
- return NULL;
- } break;
-
- case BuiltinProc_append: {
- ir_emit_comment(proc, str_lit("append"));
- gbAllocator a = proc->module->allocator;
-
- Type *value_type = type_of_expr(proc->module->info, ce->args[0]);
- irAddr array_addr = ir_build_addr(proc, ce->args[0]);
- irValue *array_ptr = array_addr.addr;
- if (is_double_pointer(ir_type(array_ptr))) {
- array_ptr = ir_addr_load(proc, array_addr);
- }
- Type *type = ir_type(array_ptr);
- {
- TokenPos pos = ast_node_token(ce->args[0]).pos;
- GB_ASSERT_MSG(is_type_pointer(type), "%.*s(%td) %s",
- LIT(pos.file), pos.line,
- type_to_string(type));
- }
- type = base_type(type_deref(type));
- Type *elem_type = NULL;
- bool is_slice = false;
- if (is_type_dynamic_array(type)) {
- elem_type = type->DynamicArray.elem;
- } else if (is_type_slice(type)) {
- is_slice = true;
- elem_type = type->Slice.elem;
- } else {
- GB_PANIC("Invalid type to append");
- }
-
- irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type));
- irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type));
-
- array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
-
- isize arg_index = 0;
- isize arg_count = 0;
- for_array(i, ce->args) {
- AstNode *a = ce->args[i];
- Type *at = base_type(type_of_expr(proc->module->info, a));
- if (at->kind == Type_Tuple) {
- arg_count += at->Tuple.variable_count;
- } else {
- arg_count++;
- }
- }
-
- irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count);
- bool vari_expand = ce->ellipsis.pos.line != 0;
-
- for_array(i, ce->args) {
- irValue *a = ir_build_expr(proc, ce->args[i]);
- Type *at = ir_type(a);
- if (at->kind == Type_Tuple) {
- for (isize i = 0; i < at->Tuple.variable_count; i++) {
- Entity *e = at->Tuple.variables[i];
- irValue *v = ir_emit_struct_ev(proc, a, i);
- args[arg_index++] = v;
- }
- } else {
- args[arg_index++] = a;
- }
- }
-
- if (!vari_expand) {
- for (isize i = 1; i < arg_count; i++) {
- args[i] = ir_emit_conv(proc, args[i], elem_type);
- }
- }
-
- if (!vari_expand) {
- ir_emit_comment(proc, str_lit("variadic call argument generation"));
- Type *slice_type = make_type_slice(a, elem_type);
- irValue *slice = ir_add_local_generated(proc, slice_type);
- isize slice_len = arg_count-1;
-
- if (slice_len > 0) {
- irValue *base_array = ir_add_local_generated(proc, make_type_array(a, elem_type, slice_len));
-
- for (isize i = 1; i < arg_count; i++) {
- irValue *addr = ir_emit_array_epi(proc, base_array, i-1);
- ir_emit_store(proc, addr, args[i]);
- }
-
- irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
- irValue *len = ir_const_int(a, slice_len);
- ir_fill_slice(proc, slice, base_elem, len, len);
- }
-
- arg_count = 2;
- args[arg_count-1] = ir_emit_load(proc, slice);
- }
-
- irValue *item_slice = args[1];
- irValue *items = ir_slice_elem(proc, item_slice);
- irValue *item_count = ir_slice_count(proc, item_slice);
-
- irValue **daa_args = gb_alloc_array(a, irValue *, 5);
- daa_args[0] = array_ptr;
- daa_args[1] = elem_size;
- daa_args[2] = elem_align;
- daa_args[3] = ir_emit_conv(proc, items, t_rawptr);
- daa_args[4] = ir_emit_conv(proc, item_count, t_int);
-
- if (is_slice) {
- return ir_emit_global_call(proc, "__slice_append", daa_args, 5);
- }
- return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
- } break;
-
- case BuiltinProc_delete: {
- ir_emit_comment(proc, str_lit("delete"));
- irValue *map = ir_build_expr(proc, ce->args[0]);
- irValue *key = ir_build_expr(proc, ce->args[1]);
- Type *map_type = ir_type(map);
- GB_ASSERT(is_type_dynamic_map(map_type));
- Type *key_type = base_type(map_type)->Map.key;
-
- irValue *addr = ir_address_from_load_or_generate_local(proc, map);
-
- gbAllocator a = proc->module->allocator;
- irValue **args = gb_alloc_array(a, irValue *, 2);
- args[0] = ir_gen_map_header(proc, addr, map_type);
- args[1] = ir_gen_map_key(proc, key, key_type);
- return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2);
- } break;
-
-
- case BuiltinProc_assert: {
- ir_emit_comment(proc, str_lit("assert"));
- irValue *cond = ir_build_expr(proc, ce->args[0]);
- GB_ASSERT(is_type_boolean(ir_type(cond)));
-
- cond = ir_emit_comp(proc, Token_CmpEq, cond, v_false);
- irBlock *err = ir_new_block(proc, NULL, "builtin.assert.err");
- irBlock *done = ir_new_block(proc, NULL, "builtin.assert.done");
-
- ir_emit_if(proc, cond, err, done);
- ir_start_block(proc, err);
-
- // TODO(bill): Cleanup allocations here
- Token token = ast_node_token(ce->args[0]);
- TokenPos pos = token.pos;
- gbString expr = expr_to_string(ce->args[0]);
- isize expr_len = gb_string_length(expr);
- String expr_str = {};
- expr_str.text = cast(u8 *)gb_alloc_copy_align(proc->module->allocator, expr, expr_len, 1);
- expr_str.len = expr_len;
- gb_string_free(expr);
-
-
- irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
- args[0] = ir_const_string(proc->module->allocator, pos.file);
- args[1] = ir_const_int(proc->module->allocator, pos.line);
- args[2] = ir_const_int(proc->module->allocator, pos.column);
- args[3] = ir_const_string(proc->module->allocator, expr_str);
- ir_emit_global_call(proc, "__assert", args, 4);
-
- ir_emit_jump(proc, done);
- ir_start_block(proc, done);
-
- return cond;
- } break;
-
- case BuiltinProc_panic: {
- ir_emit_comment(proc, str_lit("panic"));
- irValue *msg = ir_build_expr(proc, ce->args[0]);
- GB_ASSERT(is_type_string(ir_type(msg)));
-
- Token token = ast_node_token(ce->args[0]);
- TokenPos pos = token.pos;
-
- irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
- args[0] = ir_const_string(proc->module->allocator, pos.file);
- args[1] = ir_const_int(proc->module->allocator, pos.line);
- args[2] = ir_const_int(proc->module->allocator, pos.column);
- args[3] = msg;
- ir_emit_global_call(proc, "__panic", args, 4);
-
- return NULL;
- } break;
-
-
- case BuiltinProc_copy: {
- ir_emit_comment(proc, str_lit("copy"));
- // copy :: proc(dst, src: []Type) -> int
- AstNode *dst_node = ce->args[0];
- AstNode *src_node = ce->args[1];
- irValue *dst_slice = ir_build_expr(proc, dst_node);
- irValue *src_slice = ir_build_expr(proc, src_node);
- Type *slice_type = base_type(ir_type(dst_slice));
- GB_ASSERT(slice_type->kind == Type_Slice);
- Type *elem_type = slice_type->Slice.elem;
- i64 size_of_elem = type_size_of(proc->module->allocator, elem_type);
-
- irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr);
- irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr);
-
- irValue *len_dst = ir_slice_count(proc, dst_slice);
- irValue *len_src = ir_slice_count(proc, src_slice);
-
- irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src);
- irValue *len = ir_emit_select(proc, cond, len_dst, len_src);
-
- irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem);
- irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int);
-
- irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
- args[0] = dst;
- args[1] = src;
- args[2] = byte_count;
-
- ir_emit_global_call(proc, "__mem_copy", args, 3);
-
- return len;
- } break;
- case BuiltinProc_swizzle: {
- ir_emit_comment(proc, str_lit("swizzle.begin"));
- irAddr vector_addr = ir_build_addr(proc, ce->args[0]);
- isize index_count = ce->args.count-1;
- if (index_count == 0) {
- return ir_addr_load(proc, vector_addr);
- }
- irValue *src = vector_addr.addr;
- irValue *dst = ir_add_local_generated(proc, tv.type);
-
- for (i32 i = 1; i < ce->args.count; i++) {
- TypeAndValue tv = type_and_value_of_expr(proc->module->info, ce->args[i]);
- GB_ASSERT(is_type_integer(tv.type));
- GB_ASSERT(tv.value.kind == ExactValue_Integer);
-
- i32 src_index = cast(i32)i128_to_i64(tv.value.value_integer);
- i32 dst_index = i-1;
-
- irValue *src_elem = ir_emit_array_epi(proc, src, src_index);
- irValue *dst_elem = ir_emit_array_epi(proc, dst, dst_index);
-
- ir_emit_store(proc, dst_elem, ir_emit_load(proc, src_elem));
- }
- ir_emit_comment(proc, str_lit("swizzle.end"));
- return ir_emit_load(proc, dst);
- // return ir_emit(proc, ir_instr_vector_shuffle(proc, vector, indices, index_count));
- } break;
-
- case BuiltinProc_complex: {
- ir_emit_comment(proc, str_lit("complex"));
- irValue *real = ir_build_expr(proc, ce->args[0]);
- irValue *imag = ir_build_expr(proc, ce->args[1]);
- irValue *dst = ir_add_local_generated(proc, tv.type);
-
- Type *ft = base_complex_elem_type(tv.type);
- real = ir_emit_conv(proc, real, ft);
- imag = ir_emit_conv(proc, imag, ft);
- ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), real);
- ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), imag);
-
- return ir_emit_load(proc, dst);
- } break;
-
- case BuiltinProc_real: {
- ir_emit_comment(proc, str_lit("real"));
- irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *real = ir_emit_struct_ev(proc, val, 0);
- return ir_emit_conv(proc, real, tv.type);
- } break;
- case BuiltinProc_imag: {
- ir_emit_comment(proc, str_lit("imag"));
- irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *imag = ir_emit_struct_ev(proc, val, 1);
- return ir_emit_conv(proc, imag, tv.type);
- } break;
-
- case BuiltinProc_conj: {
- ir_emit_comment(proc, str_lit("conj"));
- irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *res = NULL;
- Type *t = ir_type(val);
- if (is_type_complex(t)) {
- res = ir_add_local_generated(proc, tv.type);
- irValue *real = ir_emit_struct_ev(proc, val, 0);
- irValue *imag = ir_emit_struct_ev(proc, val, 1);
- imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
- ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real);
- ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag);
- }
- return ir_emit_load(proc, res);
- } break;
-
- case BuiltinProc_slice_ptr: {
- ir_emit_comment(proc, str_lit("slice_ptr"));
- irValue *ptr = ir_build_expr(proc, ce->args[0]);
- irValue *count = ir_build_expr(proc, ce->args[1]);
- count = ir_emit_conv(proc, count, t_int);
- irValue *capacity = count;
- if (ce->args.count > 2) {
- capacity = ir_build_expr(proc, ce->args[2]);
- capacity = ir_emit_conv(proc, capacity, t_int);
- }
-
- Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr)));
- irValue *slice = ir_add_local_generated(proc, slice_type);
- ir_fill_slice(proc, slice, ptr, count, capacity);
- return ir_emit_load(proc, slice);
- } break;
-
- case BuiltinProc_slice_to_bytes: {
- ir_emit_comment(proc, str_lit("slice_to_bytes"));
- irValue *s = ir_build_expr(proc, ce->args[0]);
- Type *t = base_type(ir_type(s));
- if (is_type_u8_slice(t)) {
- return ir_emit_conv(proc, s, tv.type);
- }
- irValue *slice = ir_add_local_generated(proc, tv.type);
- i64 elem_size = type_size_of(proc->module->allocator, t->Slice.elem);
-
- irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
- irValue *count = ir_slice_count(proc, s);
- irValue *capacity = ir_slice_capacity(proc, s);
- count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int);
- capacity = ir_emit_arith(proc, Token_Mul, capacity, ir_const_int(proc->module->allocator, elem_size), t_int);
- ir_fill_slice(proc, slice, ptr, count, capacity);
- return ir_emit_load(proc, slice);
- } break;
-
- case BuiltinProc_min: {
- ir_emit_comment(proc, str_lit("min"));
- Type *t = type_of_expr(proc->module->info, expr);
- irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t);
- irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t);
- irValue *cond = ir_emit_comp(proc, Token_Lt, x, y);
- return ir_emit_select(proc, cond, x, y);
- } break;
-
- case BuiltinProc_max: {
- ir_emit_comment(proc, str_lit("max"));
- Type *t = type_of_expr(proc->module->info, expr);
- irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t);
- irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t);
- irValue *cond = ir_emit_comp(proc, Token_Gt, x, y);
- return ir_emit_select(proc, cond, x, y);
- } break;
-
- case BuiltinProc_abs: {
- ir_emit_comment(proc, str_lit("abs"));
- irValue *x = ir_build_expr(proc, ce->args[0]);
- Type *t = ir_type(x);
- if (is_type_complex(t)) {
- gbAllocator a = proc->module->allocator;
- i64 sz = 8*type_size_of(a, t);
- irValue **args = gb_alloc_array(a, irValue *, 1);
- args[0] = x;
- switch (sz) {
- case 64: return ir_emit_global_call(proc, "__abs_complex64", args, 1);
- case 128: return ir_emit_global_call(proc, "__abs_complex128", args, 1);
- }
- GB_PANIC("Unknown complex type");
- }
- irValue *zero = ir_emit_conv(proc, v_zero, t);
- irValue *cond = ir_emit_comp(proc, Token_Lt, x, zero);
- irValue *neg = ir_emit(proc, ir_instr_unary_op(proc, Token_Sub, x, t));
- return ir_emit_select(proc, cond, neg, x);
- } break;
-
- case BuiltinProc_clamp: {
- ir_emit_comment(proc, str_lit("clamp"));
- Type *t = type_of_expr(proc->module->info, expr);
- return ir_emit_clamp(proc, t,
- ir_build_expr(proc, ce->args[0]),
- ir_build_expr(proc, ce->args[1]),
- ir_build_expr(proc, ce->args[2]));
- } break;
- }
+ Entity *e = entity_of_ident(proc->module->info, p);
+ if (e != NULL && e->kind == Entity_Builtin) {
+ return ir_build_builtin_proc(proc, expr, tv, e);
}
}
@@ -5794,9 +5776,8 @@ void ir_build_range_interval(irProcedure *proc, AstNodeBinaryExpr *node, Type *v
}
void ir_store_type_case_implicit(irProcedure *proc, AstNode *clause, irValue *value) {
- Entity **found = map_get(&proc->module->info->implicits, hash_pointer(clause));
- GB_ASSERT(found != NULL);
- Entity *e = *found; GB_ASSERT(e != NULL);
+ Entity *e = implicit_entity_of_node(proc->module->info, clause);
+ GB_ASSERT(e != NULL);
irValue *x = ir_add_local(proc, e, NULL);
ir_emit_store(proc, x, value);
}
@@ -5936,9 +5917,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
AstNode *ident = pd->name;
GB_ASSERT(ident->kind == AstNode_Ident);
Entity *e = entity_of_ident(proc->module->info, ident);
- DeclInfo **decl_info = map_get(&proc->module->info->entities, hash_pointer(e));
- GB_ASSERT(decl_info != NULL);
- DeclInfo *dl = *decl_info;
+ DeclInfo *dl = decl_info_of_entity(proc->module->info, e);
if (pd->body != NULL) {
CheckerInfo *info = proc->module->info;
@@ -6599,13 +6578,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_start_block(proc, next);
}
- Entity *case_entity = NULL;
- {
- Entity **found = map_get(&proc->module->info->implicits, hash_pointer(clause));
- GB_ASSERT(found != NULL);
- case_entity = *found;
- }
-
+ Entity *case_entity = implicit_entity_of_node(proc->module->info, clause);
irValue *value = parent_value;
@@ -6771,9 +6744,8 @@ void ir_begin_procedure_body(irProcedure *proc) {
array_init(&proc->children, heap_allocator());
array_init(&proc->branch_blocks, heap_allocator());
- DeclInfo **found = map_get(&proc->module->info->entities, hash_pointer(proc->entity));
- if (found != NULL) {
- DeclInfo *decl = *found;
+ DeclInfo *decl = decl_info_of_entity(proc->module->info, proc->entity);
+ if (decl != NULL) {
for_array(i, decl->labels) {
BlockLabel bl = decl->labels[i];
irBranchBlocks bb = {bl.label, NULL, NULL};
@@ -6866,9 +6838,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
CheckerInfo *info = m->info;
Entity *e = proc->entity;
String filename = e->token.pos.file;
- AstFile **found = map_get(&info->files, hash_string(filename));
- GB_ASSERT(found != NULL);
- AstFile *f = *found;
+ AstFile *f = ast_file_of_filename(info, filename);
irDebugInfo *di_file = NULL;
irDebugInfo **di_file_found = map_get(&m->debug_info, hash_pointer(f));