diff options
Diffstat (limited to 'src/tilde_const.cpp')
| -rw-r--r-- | src/tilde_const.cpp | 1040 |
1 files changed, 1040 insertions, 0 deletions
diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp new file mode 100644 index 000000000..f9187e3e1 --- /dev/null +++ b/src/tilde_const.cpp @@ -0,0 +1,1040 @@ +gb_internal bool cg_is_expr_constant_zero(Ast *expr) { + GB_ASSERT(expr != nullptr); + auto v = exact_value_to_integer(expr->tav.value); + if (v.kind == ExactValue_Integer) { + return big_int_cmp_zero(&v.value_integer) == 0; + } + return false; +} + +gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) { + GB_ASSERT(m != nullptr); + Type *original_type = type; + type = core_type(type); + i64 size = type_size_of(type); + i64 align = type_align_of(type); + TB_DataType dt = cg_data_type(type); + if (TB_IS_VOID_TYPE(dt)) { + char name[32] = {}; + gb_snprintf(name, 31, "cnil$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, size, align, 0); + + TB_Symbol *symbol = cast(TB_Symbol *)global; + if (p) { + TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); + return cg_lvalue_addr(node, type); + } else { + return cg_value(symbol, type); + } + } + + if (is_type_internally_pointer_like(type)) { + return cg_value(tb_inst_uint(p->func, dt, 0), type); + } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type) || is_type_typeid(type)) { + return cg_value(tb_inst_uint(p->func, dt, 0), type); + } else if (is_type_float(type)) { + switch (size) { + case 2: + return cg_value(tb_inst_uint(p->func, dt, 0), type); + case 4: + return cg_value(tb_inst_float32(p->func, 0), type); + case 8: + return cg_value(tb_inst_float64(p->func, 0), type); + } + } + GB_PANIC("TODO(bill): cg_const_nil %s", type_to_string(original_type)); + return {}; +} + +gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { + return cg_const_nil(p->module, p, type); +} + +gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset); +gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type); + +gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) { + // Source_Code_Location :: struct { + // file_path: string, + // line, column: i32, + // procedure: string, + // } + + i64 file_path_offset = type_offset_of(t_source_code_location, 0); + i64 line_offset = type_offset_of(t_source_code_location, 1); + i64 column_offset = type_offset_of(t_source_code_location, 2); + i64 procedure_offset = type_offset_of(t_source_code_location, 3); + + String file_path = get_file_path_string(pos.file_id); + if (file_path.len != 0) { + cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset); + } + + void *line_ptr = tb_global_add_region(m->mod, global, offset+line_offset, 4); + void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4); + cg_write_int_at_ptr(line_ptr, pos.line, t_i32); + cg_write_int_at_ptr(column_ptr, pos.column, t_i32); + + if (proc_name.len != 0) { + cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset); + } +} + + +gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) { + cgModule *m = p->module; + char name[32] = {}; + gb_snprintf(name, 31, "scl$%u", 1+m->const_nil_guid.fetch_add(1)); + + TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, t_source_code_location), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_source_code_location), type_align_of(t_source_code_location), 6); + + cg_global_source_code_location_const(m, proc_name, pos, global, 0); + + TB_Node *ptr = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); + return cg_lvalue_addr(ptr, t_source_code_location); +} + + + +gb_internal void cg_write_big_int_at_ptr(void *dst, BigInt const *a, Type *original_type) { + GB_ASSERT(build_context.endian_kind == TargetEndian_Little); + size_t sz = cast(size_t)type_size_of(original_type); + if (big_int_is_zero(a)) { + gb_memset(dst, 0, sz); + return; + } + u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will be fine :P + u8 *rop = cast(u8 *)rop64; + + size_t max_count = 0; + size_t written = 0; + size_t size = 1; + size_t nails = 0; + mp_endian endian = MP_LITTLE_ENDIAN; + + max_count = mp_pack_count(a, nails, size); + if (sz < max_count) { + debug_print_big_int(a); + gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);; + } + GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu, type %s", max_count, sz, written, type_to_string(original_type)); + GB_ASSERT(gb_size_of(rop64) >= sz); + + mp_err err = mp_pack(rop, sz, &written, + MP_LSB_FIRST, + size, endian, nails, + a); + GB_ASSERT(err == MP_OKAY); + + if (!is_type_endian_little(original_type)) { + for (size_t i = 0; i < sz/2; i++) { + u8 tmp = rop[i]; + rop[i] = rop[sz-1-i]; + rop[sz-1-i] = tmp; + } + } + + gb_memcopy(dst, rop, sz); + return; +} + + +gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type) { + ExactValue v = exact_value_i64(i); + cg_write_big_int_at_ptr(dst, &v.value_integer, original_type); +} +gb_internal void cg_write_uint_at_ptr(void *dst, u64 i, Type *original_type) { + ExactValue v = exact_value_u64(i); + cg_write_big_int_at_ptr(dst, &v.value_integer, original_type); +} + +gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset) { + GB_ASSERT(is_type_string(type)); + + char name[32] = {}; + gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *str_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + i64 size = str.len+1; + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, size, 1, 1); + u8 *data = cast(u8 *)tb_global_add_region(m->mod, str_global, 0, size); + gb_memcopy(data, str.text, str.len); + data[str.len] = 0; + + if (is_type_cstring(type)) { + if (global) { + tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global); + } + return str_global; + } + + if (global == nullptr) { + gb_snprintf(name, 31, "cstr$%u", 1+m->const_nil_guid.fetch_add(1)); + global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(type), type_align_of(type), 2); + } + + tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global); + void *len_ptr = tb_global_add_region(m->mod, global, offset+build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(len_ptr, str.len, t_int); + + return global; +} + +gb_internal bool cg_elem_type_can_be_constant(Type *t) { + t = base_type(t); + if (t == t_invalid) { + return false; + } + if (is_type_dynamic_array(t) || is_type_map(t)) { + return false; + } + return true; +} + + +gb_internal bool cg_is_elem_const(Ast *elem, Type *elem_type) { + if (!cg_elem_type_can_be_constant(elem_type)) { + return false; + } + if (elem->kind == Ast_FieldValue) { + elem = elem->FieldValue.value; + } + TypeAndValue tav = type_and_value_of_expr(elem); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type)); + return tav.value.kind != ExactValue_Invalid; +} + +gb_internal bool cg_is_nested_possibly_constant(Type *ft, Selection const &sel, Ast *elem) { + GB_ASSERT(!sel.indirect); + for (i32 index : sel.index) { + Type *bt = base_type(ft); + switch (bt->kind) { + case Type_Struct: + // if (bt->Struct.is_raw_union) { + // return false; + // } + ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + ft = bt->Array.elem; + break; + default: + return false; + } + } + return cg_is_elem_const(elem, ft); +} + +gb_internal i64 cg_global_const_calculate_region_count_from_basic_type(Type *type) { + type = core_type(type); + + switch (type->kind) { + case Type_Basic: + switch (type->Basic.kind) { + case Basic_string: // ^u8 + int + case Basic_any: // rawptr + typeid + return 2; + } + return 1; + case Type_Pointer: + case Type_MultiPointer: + return 2; // allows for offsets + case Type_Proc: + return 1; + case Type_Slice: + return 3; // alows for offsets + case Type_DynamicArray: + return 5; + case Type_Map: + return 4; + + case Type_Enum: + case Type_BitSet: + return 1; + + case Type_RelativePointer: + case Type_RelativeMultiPointer: + return 2; // allows for offsets + + case Type_Matrix: + return 1; + + case Type_Array: + { + Type *elem = type->Array.elem; + i64 count = cg_global_const_calculate_region_count_from_basic_type(elem); + return count*type->Array.count; + } + case Type_EnumeratedArray: + { + Type *elem = type->EnumeratedArray.elem; + i64 count = cg_global_const_calculate_region_count_from_basic_type(elem); + return count*type->EnumeratedArray.count; + } + + case Type_Struct: + if (type->Struct.is_raw_union) { + i64 max_count = 0; + for (Entity *f : type->Struct.fields) { + i64 count = cg_global_const_calculate_region_count_from_basic_type(f->type); + max_count = gb_max(count, max_count); + } + return max_count; + } else { + i64 max_count = 0; + for (Entity *f : type->Struct.fields) { + max_count += cg_global_const_calculate_region_count_from_basic_type(f->type); + } + return max_count; + } + break; + case Type_Union: + { + i64 max_count = 0; + for (Type *t : type->Union.variants) { + i64 count = cg_global_const_calculate_region_count_from_basic_type(t); + max_count = gb_max(count, max_count); + } + return max_count+1; + } + break; + + default: + GB_PANIC("TODO(bill): %s", type_to_string(type)); + break; + } + return -1; +} +gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value, Type *type) { + Type *bt = base_type(type); + if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + if (is_type_rune_array(type)) { + return 1; + } + + Type *et = base_array_type(type); + i64 base_count = 2; + if (is_type_cstring(et)) { + base_count = 1; + } + return base_count * bt->Array.count; + } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { + return 1; + } else if (is_type_array(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_String && + value.kind != ExactValue_Compound) { + Type *elem = type->Array.elem; + + i64 base_count = cg_global_const_calculate_region_count(value, elem); + return base_count * type->Array.count; + } else if (is_type_matrix(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_Compound) { + return 1; + } else if (is_type_simd_vector(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_Compound) { + return 1; + } + + isize count = 0; + switch (value.kind) { + case ExactValue_Invalid: + return 0; + case ExactValue_Bool: + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Typeid: + case ExactValue_Complex: + case ExactValue_Quaternion: + return 1; + case ExactValue_Pointer: + return 2; + + case ExactValue_Procedure: + return 1; + + case ExactValue_String: + if (is_type_string(type)) { + return 3; + } else if (is_type_cstring(type) || is_type_array_like(type)) { + return 2; + } + return 3; + + case ExactValue_Compound: { + ast_node(cl, CompoundLit, value.value_compound); + Type *bt = base_type(type); + switch (bt->kind) { + case Type_Struct: + if (cl->elems[0]->kind == Ast_FieldValue) { + for (isize i = 0; i < cl->elems.count; i++) { + ast_node(fv, FieldValue, cl->elems[i]); + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, false); + GB_ASSERT(!sel.indirect); + + Entity *f = bt->Struct.fields[sel.index[0]]; + + if (!cg_elem_type_can_be_constant(f->type)) { + continue; + } + + if (sel.index.count == 1) { + count += cg_global_const_calculate_region_count(fv->value->tav.value, f->type); + } else { + count += 1; // just in case + if (cg_is_nested_possibly_constant(type, sel, fv->value)) { + Type *cv_type = sel.entity->type; + count += cg_global_const_calculate_region_count(fv->value->tav.value, cv_type); + } + } + } + } else { + for_array(i, cl->elems) { + i64 field_index = i; + Ast *elem = cl->elems[i]; + TypeAndValue tav = elem->tav; + Entity *f = bt->Struct.fields[field_index]; + if (!cg_elem_type_can_be_constant(f->type)) { + continue; + } + + ExactValue value = {}; + if (tav.mode != Addressing_Invalid) { + value = tav.value; + } + count += cg_global_const_calculate_region_count(value, type); + } + } + break; + case Type_Array: + case Type_EnumeratedArray: + case Type_SimdVector: { + Type *et = base_array_type(bt); + if (!cg_elem_type_can_be_constant(et)) { + break; + } + for (Ast *elem : cl->elems) { + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + ExactValue const &value = elem->FieldValue.value->tav.value; + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + for (i64 i = lo; i < hi; i++) { + count += cg_global_const_calculate_region_count(value, et); + } + } else { + count += cg_global_const_calculate_region_count(value, et); + } + } else { + ExactValue const &value = elem->tav.value; + count += cg_global_const_calculate_region_count(value, et); + } + } + } break; + + case Type_BitSet: + return 1; + case Type_Matrix: + return 1; + + case Type_Slice: + return 3; + + default: + GB_PANIC("TODO(bill): %s", type_to_string(type)); + break; + } + }break; + } + return count; +} + +gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *type, ExactValue const &value, TB_Global *global, i64 base_offset); + +gb_internal bool cg_global_const_add_region(cgModule *m, ExactValue const &value, Type *type, TB_Global *global, i64 offset) { + GB_ASSERT(is_type_endian_little(type)); + GB_ASSERT(!is_type_different_to_arch_endianness(type)); + + GB_ASSERT(global != nullptr); + + Type *bt = base_type(type); + i64 size = type_size_of(type); + if (value.kind == ExactValue_Invalid) { + return false; + } + if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + if (is_type_rune_array(type)) { + i64 count = type->Array.count; + Rune rune; + isize rune_offset = 0; + isize width = 1; + String s = value.value_string; + + Rune *runes = cast(Rune *)tb_global_add_region(m->mod, global, offset, count*4); + + for (i64 i = 0; i < count && rune_offset < s.len; i++) { + width = utf8_decode(s.text+rune_offset, s.len-rune_offset, &rune); + runes[i] = rune; + rune_offset += width; + + } + GB_ASSERT(offset == s.len); + return true; + } + Type *et = bt->Array.elem; + i64 elem_size = type_size_of(et); + + for (i64 i = 0; i < bt->Array.count; i++) { + cg_global_const_add_region(m, value, et, global, offset+(i * elem_size)); + } + return true; + } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { + u8 *dst = cast(u8 *)tb_global_add_region(m->mod, global, offset, size); + gb_memcopy(dst, value.value_string.text, gb_min(value.value_string.len, size)); + return true; + } else if (is_type_array(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_String && + value.kind != ExactValue_Compound) { + + Type *et = bt->Array.elem; + i64 elem_size = type_size_of(et); + + for (i64 i = 0; i < bt->Array.count; i++) { + cg_global_const_add_region(m, value, et, global, offset+(i * elem_size)); + } + + return true; + } else if (is_type_matrix(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_Compound) { + GB_PANIC("TODO(bill): matrices"); + + i64 row = bt->Matrix.row_count; + i64 column = bt->Matrix.column_count; + GB_ASSERT(row == column); + + Type *elem = bt->Matrix.elem; + + i64 elem_size = type_size_of(elem); + gb_unused(elem_size); + + // 1 region in memory, not many + + return true; + } else if (is_type_simd_vector(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_Compound) { + + GB_PANIC("TODO(bill): #simd vectors"); + + Type *et = type->SimdVector.elem; + i64 elem_size = type_size_of(et); + gb_unused(elem_size); + + // 1 region in memory, not many + + return true; + } + + + switch (value.kind) { + case ExactValue_Bool: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + bool *res = cast(bool *)tb_global_add_region(m->mod, global, offset, size); + *res = !!value.value_bool; + } + break; + + case ExactValue_Integer: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + void *res = tb_global_add_region(m->mod, global, offset, size); + cg_write_big_int_at_ptr(res, &value.value_integer, type); + } + break; + + case ExactValue_Float: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + f64 f = exact_value_to_f64(value); + void *res = tb_global_add_region(m->mod, global, offset, size); + switch (size) { + case 2: *(u16 *)res = f32_to_f16(cast(f32)f); break; + case 4: *(f32 *)res = cast(f32)f; break; + case 8: *(f64 *)res = cast(f64)f; break; + } + } + break; + + case ExactValue_Pointer: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + void *res = tb_global_add_region(m->mod, global, offset, size); + *(u64 *)res = exact_value_to_u64(value); + } + break; + + case ExactValue_String: + if (is_type_array_like(type)) { + GB_ASSERT(global != nullptr); + void *data = tb_global_add_region(m->mod, global, offset, size); + gb_memcopy(data, value.value_string.text, gb_min(value.value_string.len, size)); + } else { + cg_global_const_string(m, value.value_string, type, global, offset); + } + break; + + case ExactValue_Typeid: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + void *dst = tb_global_add_region(m->mod, global, offset, size); + u64 id = cg_typeid_as_u64(m, value.value_typeid); + cg_write_uint_at_ptr(dst, id, t_typeid); + } + break; + + case ExactValue_Compound: + { + TB_Global *out_global = cg_global_const_comp_literal(m, type, value, global, offset); + GB_ASSERT(out_global == global); + } + break; + + case ExactValue_Procedure: + GB_PANIC("TODO(bill): nested procedure values/literals\n"); + break; + case ExactValue_Complex: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + Complex128 c = {}; + if (value.value_complex) { + c = *value.value_complex; + } + void *res = tb_global_add_region(m->mod, global, offset, size); + switch (size) { + case 4: + ((u16 *)res)[0] = f32_to_f16(cast(f32)c.real); + ((u16 *)res)[1] = f32_to_f16(cast(f32)c.imag); + break; + case 8: + ((f32 *)res)[0] = cast(f32)c.real; + ((f32 *)res)[1] = cast(f32)c.imag; + break; + case 16: + ((f64 *)res)[0] = cast(f64)c.real; + ((f64 *)res)[1] = cast(f64)c.imag; + break; + } + } + break; + case ExactValue_Quaternion: + { + GB_ASSERT_MSG(!is_type_array_like(bt), "%s", type_to_string(type)); + // @QuaternionLayout + Quaternion256 q = {}; + if (value.value_quaternion) { + q = *value.value_quaternion; + } + void *res = tb_global_add_region(m->mod, global, offset, size); + switch (size) { + case 8: + ((u16 *)res)[0] = f32_to_f16(cast(f32)q.imag); + ((u16 *)res)[1] = f32_to_f16(cast(f32)q.jmag); + ((u16 *)res)[2] = f32_to_f16(cast(f32)q.kmag); + ((u16 *)res)[3] = f32_to_f16(cast(f32)q.real); + break; + case 16: + ((f32 *)res)[0] = cast(f32)q.imag; + ((f32 *)res)[1] = cast(f32)q.jmag; + ((f32 *)res)[2] = cast(f32)q.kmag; + ((f32 *)res)[3] = cast(f32)q.real; + break; + case 32: + ((f64 *)res)[0] = cast(f64)q.imag; + ((f64 *)res)[1] = cast(f64)q.jmag; + ((f64 *)res)[2] = cast(f64)q.kmag; + ((f64 *)res)[3] = cast(f64)q.real; + break; + } + } + break; + default: + GB_PANIC("%s", type_to_string(type)); + break; + } + return true; +} + + +gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *original_type, ExactValue const &value, TB_Global *global, i64 base_offset) { + GB_ASSERT(value.kind == ExactValue_Compound); + Ast *value_compound = value.value_compound; + ast_node(cl, CompoundLit, value_compound); + + TEMPORARY_ALLOCATOR_GUARD(); + + if (global == nullptr) { + char name[32] = {}; + gb_snprintf(name, 31, "complit$%u", 1+m->const_nil_guid.fetch_add(1)); + global = tb_global_create(m->mod, -1, name, cg_debug_type(m, original_type), TB_LINKAGE_PRIVATE); + i64 size = type_size_of(original_type); + i64 align = type_align_of(original_type); + + // READ ONLY? + TB_ModuleSection *section = nullptr; + if (is_type_string(original_type) || is_type_cstring(original_type)) { + section = tb_module_get_rdata(m->mod); + } else { + section = tb_module_get_data(m->mod); + } + + if (cl->elems.count == 0) { + tb_global_set_storage(m->mod, section, global, size, align, 0); + return global; + } + + + isize global_region_count = cg_global_const_calculate_region_count(value, original_type); + tb_global_set_storage(m->mod, section, global, size, align, global_region_count); + } + + if (cl->elems.count == 0) { + return global; + } + + + Type *bt = base_type(original_type); + i64 bt_size = type_size_of(bt); + + switch (bt->kind) { + case Type_Struct: + if (cl->elems[0]->kind == Ast_FieldValue) { + isize elem_count = cl->elems.count; + for (isize i = 0; i < elem_count; i++) { + ast_node(fv, FieldValue, cl->elems[i]); + String name = fv->field->Ident.token.string; + + TypeAndValue tav = fv->value->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + ExactValue value = tav.value; + + Selection sel = lookup_field(bt, name, false); + GB_ASSERT(!sel.indirect); + + if (!cg_is_nested_possibly_constant(bt, sel, fv->value)) { + continue; + } + + i64 offset = type_offset_of_from_selection(bt, sel); + cg_global_const_add_region(m, value, sel.entity->type, global, base_offset+offset); + } + } else { + for_array(i, cl->elems) { + i64 field_index = i; + Ast *elem = cl->elems[i]; + TypeAndValue tav = elem->tav; + Entity *f = bt->Struct.fields[field_index]; + if (!cg_elem_type_can_be_constant(f->type)) { + continue; + } + + i64 offset = bt->Struct.offsets[field_index]; + + ExactValue value = {}; + if (tav.mode != Addressing_Invalid) { + value = tav.value; + } + cg_global_const_add_region(m, value, f->type, global, base_offset+offset); + } + } + return global; + + case Type_Array: + case Type_EnumeratedArray: + case Type_SimdVector: + if (cl->elems[0]->kind == Ast_FieldValue) { + Type *et = base_array_type(bt); + i64 elem_size = type_size_of(et); + for (Ast *elem : cl->elems) { + ast_node(fv, FieldValue, elem); + + ExactValue const &value = fv->value->tav.value; + + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + for (i64 i = lo; i < hi; i++) { + i64 offset = i * elem_size; + cg_global_const_add_region(m, value, et, global, base_offset+offset); + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 i = exact_value_to_i64(index_tav.value); + i64 offset = i * elem_size; + cg_global_const_add_region(m, value, et, global, base_offset+offset); + } + } + } else { + Type *et = base_array_type(bt); + i64 elem_size = type_size_of(et); + i64 offset = 0; + for (Ast *elem : cl->elems) { + ExactValue const &value = elem->tav.value; + cg_global_const_add_region(m, value, et, global, base_offset+offset); + offset += elem_size; + } + } + + return global; + + case Type_BitSet: + if (bt_size > 0) { + BigInt bits = {}; + BigInt one = {}; + big_int_from_u64(&one, 1); + + for_array(i, cl->elems) { + Ast *e = cl->elems[i]; + GB_ASSERT(e->kind != Ast_FieldValue); + + TypeAndValue tav = e->tav; + if (tav.mode != Addressing_Constant) { + continue; + } + GB_ASSERT(tav.value.kind == ExactValue_Integer); + i64 v = big_int_to_i64(&tav.value.value_integer); + i64 lower = bt->BitSet.lower; + u64 index = cast(u64)(v-lower); + BigInt bit = {}; + big_int_from_u64(&bit, index); + big_int_shl(&bit, &one, &bit); + big_int_or(&bits, &bits, &bit); + } + + void *dst = tb_global_add_region(m->mod, global, base_offset, bt_size); + cg_write_big_int_at_ptr(dst, &bits, original_type); + } + return global; + + case Type_Matrix: + GB_PANIC("TODO(bill): constant compound literal for %s", type_to_string(original_type)); + break; + + case Type_Slice: + { + i64 count = gb_max(cl->elems.count, cl->max_count); + Type *elem = bt->Slice.elem; + Type *t = alloc_type_array(elem, count); + TB_Global *backing_array = cg_global_const_comp_literal(m, t, value, nullptr, 0); + + tb_global_add_symbol_reloc(m->mod, global, base_offset+0, cast(TB_Symbol *)backing_array); + + void *len_ptr = tb_global_add_region(m->mod, global, base_offset+build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(len_ptr, count, t_int); + } + return global; + } + + GB_PANIC("TODO(bill): constant compound literal for %s", type_to_string(original_type)); + return nullptr; +} + + +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { + GB_ASSERT(p != nullptr); + TB_Node *node = nullptr; + + if (is_type_untyped(type)) { + // TODO(bill): THIS IS A COMPLETE HACK, WHY DOES THIS NOT A TYPE? + GB_ASSERT(type->kind == Type_Basic); + switch (type->Basic.kind) { + case Basic_UntypedBool: + type = t_bool; + break; + case Basic_UntypedInteger: + type = t_i64; + break; + case Basic_UntypedFloat: + type = t_f64; + break; + case Basic_UntypedComplex: + type = t_complex128; + break; + case Basic_UntypedQuaternion: + type = t_quaternion256; + break; + case Basic_UntypedString: + type = t_string; + break; + case Basic_UntypedRune: + type = t_rune; + break; + case Basic_UntypedNil: + case Basic_UntypedUninit: + return cg_value(cast(TB_Node *)nullptr, type); + } + } + TB_DataType dt = cg_data_type(type); + + switch (value.kind) { + case ExactValue_Invalid: + return cg_const_nil(p, type); + + case ExactValue_Typeid: + return cg_typeid(p, value.value_typeid); + + case ExactValue_Procedure: + { + Ast *expr = unparen_expr(value.value_procedure); + if (expr->kind == Ast_ProcLit) { + cgProcedure *anon = cg_procedure_generate_anonymous(p->module, expr, p); + TB_Node *ptr = tb_inst_get_symbol_address(p->func, anon->symbol); + GB_ASSERT(are_types_identical(type, anon->type)); + return cg_value(ptr, type); + } + + Entity *e = entity_of_node(expr); + if (e != nullptr) { + TB_Symbol *found = cg_find_symbol_from_entity(p->module, e); + GB_ASSERT_MSG(found != nullptr, "could not find '%.*s'", LIT(e->token.string)); + TB_Node *ptr = tb_inst_get_symbol_address(p->func, found); + GB_ASSERT(type != nullptr); + GB_ASSERT(are_types_identical(type, e->type)); + return cg_value(ptr, type); + } + + GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure %s", expr_to_string(expr)); + } + break; + } + + switch (value.kind) { + case ExactValue_Bool: + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + return cg_value(tb_inst_uint(p->func, dt, value.value_bool), type); + + case ExactValue_Integer: + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + // GB_ASSERT(dt.raw != TB_TYPE_I128.raw); + if (is_type_unsigned(type)) { + u64 i = exact_value_to_u64(value); + return cg_value(tb_inst_uint(p->func, dt, i), type); + } else { + i64 i = exact_value_to_i64(value); + return cg_value(tb_inst_sint(p->func, dt, i), type); + } + break; + + case ExactValue_Float: + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + GB_ASSERT(dt.raw != TB_TYPE_F16.raw); + GB_ASSERT(!is_type_different_to_arch_endianness(type)); + { + f64 f = exact_value_to_f64(value); + if (type_size_of(type) == 8) { + return cg_value(tb_inst_float64(p->func, f), type); + } else { + return cg_value(tb_inst_float32(p->func, cast(f32)f), type); + } + } + break; + + case ExactValue_String: + { + GB_ASSERT(is_type_string(type)); + cgModule *m = p->module; + + String str = value.value_string; + + char name[32] = {}; + gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *cstr_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + + i64 size = str.len+1; + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), cstr_global, size, 1, 1); + u8 *data = cast(u8 *)tb_global_add_region(m->mod, cstr_global, 0, size); + gb_memcopy(data, str.text, str.len); + data[str.len] = 0; + + if (is_type_cstring(type)) { + cgValue s = cg_value(cstr_global, type); + return cg_flatten_value(p, s); + } + + gb_snprintf(name, 31, "str$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *str_global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, type_size_of(type), type_align_of(type), 2); + + tb_global_add_symbol_reloc(m->mod, str_global, 0, cast(TB_Symbol *)cstr_global); + void *len_ptr = tb_global_add_region(m->mod, str_global, build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(len_ptr, str.len, t_int); + + TB_Node *s = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)str_global); + return cg_lvalue_addr(s, type); + + } + + case ExactValue_Pointer: + return cg_value(tb_inst_uint(p->func, dt, exact_value_to_u64(value)), type); + + case ExactValue_Compound: + { + TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_comp_literal(p->module, type, value, nullptr, 0); + TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); + return cg_lvalue_addr(node, type); + } + break; + } + + + GB_ASSERT(node != nullptr); + return cg_value(node, type); +} + +gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { + return cg_const_value(p, type, exact_value_i64(i)); +} +gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) { + return cg_value(tb_inst_bool(p->func, v), type); +} + +gb_internal cgValue cg_const_string(cgProcedure *p, Type *type, String const &str) { + return cg_const_value(p, type, exact_value_string(str)); +} + +gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) { + return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); +} + |