From 0bd33882b67952d80d7123a8af09ff902c96bb56 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 21:43:42 +0100 Subject: [PATCH] Basic constant compound literal support --- src/llvm_backend_const.cpp | 134 ++++++++-------- src/tilde_const.cpp | 320 ++++++++++++++++++++++++++++++++++++- 2 files changed, 383 insertions(+), 71 deletions(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 2a121ff5d..a152e00c2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1036,86 +1036,84 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count); - if (cl->elems.count > 0) { - 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; + 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); + TypeAndValue tav = fv->value->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); - Selection sel = lookup_field(type, name, false); - GB_ASSERT(!sel.indirect); + Selection sel = lookup_field(type, name, false); + GB_ASSERT(!sel.indirect); - Entity *f = type->Struct.fields[sel.index[0]]; - i32 index = field_remapping[f->Variable.field_index]; - if (elem_type_can_be_constant(f->type)) { - if (sel.index.count == 1) { - values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + Entity *f = type->Struct.fields[sel.index[0]]; + i32 index = field_remapping[f->Variable.field_index]; + if (elem_type_can_be_constant(f->type)) { + if (sel.index.count == 1) { + values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + visited[index] = true; + } else { + if (!visited[index]) { + values[index] = lb_const_value(m, f->type, {}, false).value; visited[index] = true; - } else { - if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, false).value; - visited[index] = true; - } - unsigned idx_list_len = cast(unsigned)sel.index.count-1; - unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); + } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; + unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); - if (lb_is_nested_possibly_constant(type, sel, fv->value)) { - bool is_constant = true; - Type *cv_type = f->type; - for (isize j = 1; j < sel.index.count; j++) { - i32 index = sel.index[j]; - Type *cvt = base_type(cv_type); + if (lb_is_nested_possibly_constant(type, sel, fv->value)) { + bool is_constant = true; + Type *cv_type = f->type; + for (isize j = 1; j < sel.index.count; j++) { + i32 index = sel.index[j]; + Type *cvt = base_type(cv_type); - if (cvt->kind == Type_Struct) { - if (cvt->Struct.is_raw_union) { - // sanity check which should have been caught by `lb_is_nested_possibly_constant` - is_constant = false; - break; - } - cv_type = cvt->Struct.fields[index]->type; - - if (is_type_struct(cvt)) { - auto cv_field_remapping = lb_get_struct_remapping(m, cvt); - unsigned remapped_index = cast(unsigned)cv_field_remapping[index]; - idx_list[j-1] = remapped_index; - } else { - idx_list[j-1] = cast(unsigned)index; - } - } else if (cvt->kind == Type_Array) { - cv_type = cvt->Array.elem; - - idx_list[j-1] = cast(unsigned)index; - } else { - GB_PANIC("UNKNOWN TYPE: %s", type_to_string(cv_type)); + if (cvt->kind == Type_Struct) { + if (cvt->Struct.is_raw_union) { + // sanity check which should have been caught by `lb_is_nested_possibly_constant` + is_constant = false; + break; } + cv_type = cvt->Struct.fields[index]->type; + + if (is_type_struct(cvt)) { + auto cv_field_remapping = lb_get_struct_remapping(m, cvt); + unsigned remapped_index = cast(unsigned)cv_field_remapping[index]; + idx_list[j-1] = remapped_index; + } else { + idx_list[j-1] = cast(unsigned)index; + } + } else if (cvt->kind == Type_Array) { + cv_type = cvt->Array.elem; + + idx_list[j-1] = cast(unsigned)index; + } else { + GB_PANIC("UNKNOWN TYPE: %s", type_to_string(cv_type)); } - if (is_constant) { - LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local).value; - GB_ASSERT(LLVMIsConstant(elem_value)); - values[index] = LLVMConstInsertValue(values[index], elem_value, idx_list, idx_list_len); - } + } + if (is_constant) { + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local).value; + GB_ASSERT(LLVMIsConstant(elem_value)); + values[index] = LLVMConstInsertValue(values[index], elem_value, idx_list, idx_list_len); } } } } - } else { - for_array(i, cl->elems) { - Entity *f = type->Struct.fields[i]; - TypeAndValue tav = cl->elems[i]->tav; - ExactValue val = {}; - if (tav.mode != Addressing_Invalid) { - val = tav.value; - } - - i32 index = field_remapping[f->Variable.field_index]; - if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, val, allow_local).value; - visited[index] = true; - } + } + } else { + for_array(i, cl->elems) { + Entity *f = type->Struct.fields[i]; + TypeAndValue tav = cl->elems[i]->tav; + ExactValue val = {}; + if (tav.mode != Addressing_Invalid) { + val = tav.value; + } + + i32 index = field_remapping[f->Variable.field_index]; + if (elem_type_can_be_constant(f->type)) { + values[index] = lb_const_value(m, f->type, val, allow_local).value; + visited[index] = true; } } } diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index a036d928c..616bf7833 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -8,6 +8,7 @@ gb_internal bool cg_is_expr_constant_zero(Ast *expr) { } 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); @@ -16,7 +17,7 @@ gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, 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, nullptr, TB_LINKAGE_PRIVATE); + 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; @@ -24,7 +25,7 @@ gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) { TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); return cg_lvalue_addr(node, type); } else { - GB_PANIC("TODO(bill): cg_const_nil"); + return cg_value(symbol, type); } } @@ -50,6 +51,95 @@ 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_cstring(cgModule *m, String const &str, Type *type) { + char name[32] = {}; + gb_snprintf(name, 31, "csb$%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); + i64 size = str.len+1; + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, size, 1, 1); + u8 *data = cast(u8 *)tb_global_add_region(m->mod, global, 0, size+1); + gb_memcopy(data, str.text, str.len); + data[str.len] = 0; + return global; + +} + +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) { + if (is_type_cstring(type)) { + return cg_global_const_cstring(m, str, type); + } + GB_ASSERT(is_type_string(type)); + + char name[32] = {}; + gb_snprintf(name, 31, "csl$%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); + + + i64 size = type_size_of(type); + i64 align = type_align_of(type); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, size, align, 2); + + tb_global_add_symbol_reloc(m->mod, global, 0, cast(TB_Symbol *)cg_global_const_cstring(m, str, t_cstring)); + + void *len_ptr = tb_global_add_region(m->mod, global, build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(len_ptr, str.len, t_int); + + return global; +} + + gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, ExactValue const &value, bool allow_local = true) { TB_Node *node = nullptr; @@ -79,13 +169,15 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac break; } - GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + Type *original_type = type; 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); @@ -97,6 +189,7 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac 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)); { @@ -108,6 +201,227 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac } } break; + + case ExactValue_String: + { + TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_string(m, value.value_string, type); + 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); + } + } + + case ExactValue_Pointer: + return cg_value(tb_inst_uint(p->func, dt, exact_value_to_u64(value)), type); + + case ExactValue_Compound: + if (is_type_struct(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + if (cl->elems.count == 0) { + return cg_const_nil(m, p, original_type); + } + + Type *bt = base_type(type); + if (bt->Struct.is_raw_union) { + return cg_const_nil(m, p, original_type); + } + + TEMPORARY_ALLOCATOR_GUARD(); + + isize value_count = bt->Struct.fields.count; + cgValue * values = gb_alloc_array(temporary_allocator(), cgValue, value_count); + bool * visited = gb_alloc_array(temporary_allocator(), bool, value_count); + + + char name[32] = {}; + gb_snprintf(name, 31, "complit$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *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 = tb_module_get_rdata(m->mod); + tb_global_set_storage(m->mod, section, global, size, align, value_count); + + 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); + + // Selection sel = lookup_field(type, name, false); + // GB_ASSERT(!sel.indirect); + + // Entity *f = type->Struct.fields[sel.index[0]]; + // i32 index = field_remapping[f->Variable.field_index]; + // if (elem_type_can_be_constant(f->type)) { + // if (sel.index.count == 1) { + // values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + // visited[index] = true; + // } else { + // if (!visited[index]) { + // values[index] = lb_const_value(m, f->type, {}, false).value; + // visited[index] = true; + // } + // unsigned idx_list_len = cast(unsigned)sel.index.count-1; + // unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); + + // if (lb_is_nested_possibly_constant(type, sel, fv->value)) { + // bool is_constant = true; + // Type *cv_type = f->type; + // for (isize j = 1; j < sel.index.count; j++) { + // i32 index = sel.index[j]; + // Type *cvt = base_type(cv_type); + + // if (cvt->kind == Type_Struct) { + // if (cvt->Struct.is_raw_union) { + // // sanity check which should have been caught by `lb_is_nested_possibly_constant` + // is_constant = false; + // break; + // } + // cv_type = cvt->Struct.fields[index]->type; + + // if (is_type_struct(cvt)) { + // auto cv_field_remapping = lb_get_struct_remapping(m, cvt); + // unsigned remapped_index = cast(unsigned)cv_field_remapping[index]; + // idx_list[j-1] = remapped_index; + // } else { + // idx_list[j-1] = cast(unsigned)index; + // } + // } else if (cvt->kind == Type_Array) { + // cv_type = cvt->Array.elem; + + // idx_list[j-1] = cast(unsigned)index; + // } else { + // GB_PANIC("UNKNOWN TYPE: %s", type_to_string(cv_type)); + // } + // } + // if (is_constant) { + // LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local).value; + // GB_ASSERT(LLVMIsConstant(elem_value)); + // values[index] = LLVMConstInsertValue(values[index], elem_value, idx_list, idx_list_len); + // } + // } + // } + // } + // } + } 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 (!elem_type_can_be_constant(f->type)) { + continue; + } + + i64 offset = bt->Struct.offsets[field_index]; + i64 size = type_size_of(f->type); + + + ExactValue value = {}; + if (tav.mode != Addressing_Invalid) { + value = tav.value; + } + + GB_ASSERT(is_type_endian_little(f->type)); + GB_ASSERT(!is_type_different_to_arch_endianness(type)); + + + if (value.kind != ExactValue_Invalid) { + switch (value.kind) { + case ExactValue_Bool: + { + bool *res = cast(bool *)tb_global_add_region(m->mod, global, offset, size); + *res = !!value.value_bool; + } + break; + + case ExactValue_Integer: + { + void *res = tb_global_add_region(m->mod, global, offset, size); + cg_write_big_int_at_ptr(res, &value.value_integer, f->type); + } + break; + + case ExactValue_Float: + { + 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: + { + void *res = tb_global_add_region(m->mod, global, offset, size); + *(u64 *)res = exact_value_to_u64(value); + } + break; + + case ExactValue_String: + { + TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_string(m, value.value_string, f->type); + tb_global_add_symbol_reloc(m->mod, global, offset, symbol); + } + break; + + case ExactValue_Typeid: + { + 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_Procedure: + GB_PANIC("TODO(bill): nested procedure values/literals\n"); + break; + case ExactValue_Compound: + GB_PANIC("TODO(bill): nested compound literals\n"); + break; + + case ExactValue_Complex: + GB_PANIC("TODO(bill): nested complex literals\n"); + break; + case ExactValue_Quaternion: + GB_PANIC("TODO(bill): nested quaternions literals\n"); + break; + default: + GB_PANIC("%s", type_to_string(f->type)); + break; + } + visited[i] = true; + continue; + } + + values[i] = cg_const_value(m, p, f->type, value, allow_local); + visited[i] = true; + } + } + + 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); + } + + } else { + GB_PANIC("TODO(bill): constant compound literal for %s", type_to_string(type)); + } + break; }