Files
Odin/src/tilde_const.cpp
2023-08-07 14:40:42 +01:00

1050 lines
30 KiB
C++

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 cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node) {
String proc_name = p->name;
TokenPos pos = ast_token(node).pos;
return cg_emit_source_code_location_as_global(p, proc_name, pos);
}
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 = 0;
if (value.kind == ExactValue_Integer && value.value_integer.sign) {
i = exact_value_to_i64(value);
} else {
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)));
}