mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 01:14:40 +00:00
1050 lines
30 KiB
C++
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_ModuleSectionHandle section = 0;
|
|
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)));
|
|
}
|
|
|