Reorganize llvm_backend.cpp into separate files for easier maintenance

This commit is contained in:
gingerBill
2021-08-07 12:01:48 +01:00
parent f5e51a29b5
commit 40822be595
11 changed files with 14677 additions and 14673 deletions
+8 -14673
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -425,6 +425,23 @@ lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x);
void lb_mem_zero_addr(lbProcedure *p, LLVMValueRef ptr, Type *type);
void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
bool lb_is_expr_untyped_const(Ast *expr);
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment);
void lb_emit_init_context(lbProcedure *p, lbAddr addr);
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast);
void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint);
lbValue lb_consume_copy_elision_hint(lbProcedure *p);
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
+951
View File
@@ -0,0 +1,951 @@
bool lb_is_const(lbValue value) {
LLVMValueRef v = value.value;
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
// TODO(bill): Is this correct behaviour?
return true;
}
if (LLVMIsConstant(v)) {
return true;
}
return false;
}
bool lb_is_const_or_global(lbValue value) {
if (lb_is_const(value)) {
return true;
}
if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) {
LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value));
if (!lb_is_type_kind(t, LLVMPointerTypeKind)) {
return false;
}
LLVMTypeRef elem = LLVMGetElementType(t);
return lb_is_type_kind(elem, LLVMFunctionTypeKind);
}
return false;
}
bool lb_is_elem_const(Ast *elem, Type *elem_type) {
if (!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;
}
bool lb_is_const_nil(lbValue value) {
LLVMValueRef v = value.value;
if (LLVMIsConstant(v)) {
if (LLVMIsAConstantAggregateZero(v)) {
return true;
} else if (LLVMIsAConstantPointerNull(v)) {
return true;
}
}
return false;
}
bool lb_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;
}
String lb_get_const_string(lbModule *m, lbValue value) {
GB_ASSERT(lb_is_const(value));
GB_ASSERT(LLVMIsConstant(value.value));
Type *t = base_type(value.type);
GB_ASSERT(are_types_identical(t, t_string));
unsigned ptr_indices[1] = {0};
unsigned len_indices[1] = {1};
LLVMValueRef underlying_ptr = LLVMConstExtractValue(value.value, ptr_indices, gb_count_of(ptr_indices));
LLVMValueRef underlying_len = LLVMConstExtractValue(value.value, len_indices, gb_count_of(len_indices));
GB_ASSERT(LLVMGetConstOpcode(underlying_ptr) == LLVMGetElementPtr);
underlying_ptr = LLVMGetOperand(underlying_ptr, 0);
GB_ASSERT(LLVMIsAGlobalVariable(underlying_ptr));
underlying_ptr = LLVMGetInitializer(underlying_ptr);
size_t length = 0;
char const *text = LLVMGetAsString(underlying_ptr, &length);
isize real_length = cast(isize)LLVMConstIntGetSExtValue(underlying_len);
return make_string(cast(u8 const *)text, real_length);
}
LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
LLVMTypeRef src = LLVMTypeOf(val);
if (src == dst) {
return val;
}
if (LLVMIsNull(val)) {
return LLVMConstNull(dst);
}
GB_ASSERT(LLVMSizeOf(dst) == LLVMSizeOf(src));
LLVMTypeKind kind = LLVMGetTypeKind(dst);
switch (kind) {
case LLVMPointerTypeKind:
return LLVMConstPointerCast(val, dst);
case LLVMStructTypeKind:
return LLVMConstBitCast(val, dst);
default:
GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
}
return val;
}
lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
GB_ASSERT(is_type_pointer(value.type));
GB_ASSERT(is_type_pointer(t));
GB_ASSERT(lb_is_const(value));
lbValue res = {};
res.value = LLVMConstPointerCast(value.value, lb_type(m, t));
res.type = t;
return res;
}
LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
unsigned elem_count = LLVMCountStructElementTypes(t);
GB_ASSERT(value_count == elem_count);
for (unsigned i = 0; i < elem_count; i++) {
LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i);
values[i] = llvm_const_cast(values[i], elem_type);
}
return LLVMConstNamedStruct(t, values, value_count);
}
LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
for (unsigned i = 0; i < value_count; i++) {
values[i] = llvm_const_cast(values[i], elem_type);
}
return LLVMConstArray(elem_type, values, value_count);
}
LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
GB_ASSERT(is_type_pointer(data.type));
GB_ASSERT(are_types_identical(len.type, t_int));
LLVMValueRef vals[2] = {
data.value,
len.value,
};
return LLVMConstStructInContext(m->ctx, vals, gb_count_of(vals), false);
}
lbValue lb_const_nil(lbModule *m, Type *type) {
LLVMValueRef v = LLVMConstNull(lb_type(m, type));
return lbValue{v, type};
}
lbValue lb_const_undef(lbModule *m, Type *type) {
LLVMValueRef v = LLVMGetUndef(lb_type(m, type));
return lbValue{v, type};
}
lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
res.type = type;
return res;
}
lbValue lb_const_string(lbModule *m, String const &value) {
return lb_const_value(m, t_string, exact_value_string(value));
}
lbValue lb_const_bool(lbModule *m, Type *type, bool value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, type), value, false);
res.type = type;
return res;
}
LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
GB_ASSERT(type_size_of(type) == 2);
u16 u = f32_to_f16(f);
if (is_type_different_to_arch_endianness(type)) {
u = gb_endian_swap16(u);
}
LLVMValueRef i = LLVMConstInt(LLVMInt16TypeInContext(m->ctx), u, false);
return LLVMConstBitCast(i, lb_type(m, type));
}
LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
GB_ASSERT(type_size_of(type) == 4);
u32 u = bit_cast<u32>(f);
if (is_type_different_to_arch_endianness(type)) {
u = gb_endian_swap32(u);
}
LLVMValueRef i = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), u, false);
return LLVMConstBitCast(i, lb_type(m, type));
}
bool lb_is_expr_untyped_const(Ast *expr) {
auto const &tv = type_and_value_of_expr(expr);
if (is_type_untyped(tv.type)) {
return tv.value.kind != ExactValue_Invalid;
}
return false;
}
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) {
GB_ASSERT(is_type_typed(t));
auto const &tv = type_and_value_of_expr(expr);
return lb_const_value(m, t, tv.value);
}
lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) {
lbModule *m = p->module;
LLVMValueRef fields[4] = {};
fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)).value;
fields[1]/*line*/ = lb_const_int(m, t_i32, pos.line).value;
fields[2]/*column*/ = lb_const_int(m, t_i32, pos.column).value;
fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value;
lbValue res = {};
res.value = llvm_const_named_struct(lb_type(m, t_source_code_location), fields, gb_count_of(fields));
res.type = t_source_code_location;
return res;
}
lbValue lb_emit_source_code_location(lbProcedure *p, Ast *node) {
String proc_name = {};
if (p->entity) {
proc_name = p->entity->token.string;
}
TokenPos pos = {};
if (node) {
pos = ast_token(node).pos;
}
return lb_emit_source_code_location(p, proc_name, pos);
}
LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) {
bool is_local = allow_local && m->curr_procedure != nullptr;
bool is_const = true;
if (is_local) {
for (isize i = 0; i < count; i++) {
GB_ASSERT(values[i] != nullptr);
if (!LLVMIsConstant(values[i])) {
is_const = false;
break;
}
}
}
if (!is_const) {
lbProcedure *p = m->curr_procedure;
GB_ASSERT(p != nullptr);
lbAddr v = lb_add_local_generated(p, type, false);
lbValue ptr = lb_addr_get_ptr(p, v);
for (isize i = 0; i < count; i++) {
lbValue elem = lb_emit_array_epi(p, ptr, i);
LLVMBuildStore(p->builder, values[i], elem.value);
}
return lb_addr_load(p, v).value;
}
return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
}
LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
if (big_int_is_zero(a)) {
return LLVMConstNull(lb_type(m, original_type));
}
size_t sz = cast(size_t)type_size_of(original_type);
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);
GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu", max_count, sz, written);
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;
}
}
LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)(sz+7/8), cast(u64 *)rop);
if (big_int_is_neg(a)) {
value = LLVMConstNeg(value);
}
return value;
}
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
LLVMContextRef ctx = m->ctx;
type = default_type(type);
Type *original_type = type;
lbValue res = {};
res.type = original_type;
type = core_type(type);
value = convert_exact_value_for_type(value, type);
if (value.kind == ExactValue_Typeid) {
return lb_typeid(m, value.value_typeid);
}
if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, type);
}
if (value.kind == ExactValue_Procedure) {
Ast *expr = unparen_expr(value.value_procedure);
if (expr->kind == Ast_ProcLit) {
return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
}
Entity *e = entity_from_expr(expr);
return lb_find_procedure_value_from_entity(m, e);
}
bool is_local = allow_local && m->curr_procedure != nullptr;
// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
if (is_type_slice(type)) {
if (value.kind == ExactValue_String) {
GB_ASSERT(is_type_u8_slice(type));
res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value;
return res;
} else {
ast_node(cl, CompoundLit, value.value_compound);
isize count = cl->elems.count;
if (count == 0) {
return lb_const_nil(m, type);
}
count = gb_max(cast(isize)cl->max_count, count);
Type *elem = base_type(type)->Slice.elem;
Type *t = alloc_type_array(elem, count);
lbValue backing_array = lb_const_value(m, t, value, allow_local);
LLVMValueRef array_data = nullptr;
if (is_local) {
// NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs
// its backing data on the stack
lbProcedure *p = m->curr_procedure;
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
LLVMTypeRef llvm_type = lb_type(m, t);
array_data = LLVMBuildAlloca(p->builder, llvm_type, "");
LLVMSetAlignment(array_data, 16); // TODO(bill): Make this configurable
LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block);
LLVMBuildStore(p->builder, backing_array.value, array_data);
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, "");
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
lbAddr slice = lb_add_local_generated(p, type, false);
lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int});
return lb_addr_load(p, slice);
}
} else {
isize max_len = 7+8+1;
char *str = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
isize len = gb_snprintf(str, max_len, "csba$%x", id);
String name = make_string(cast(u8 *)str, len-1);
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str);
LLVMSetInitializer(array_data, backing_array.value);
lbValue g = {};
g.value = array_data;
g.type = t;
lb_add_entity(m, e, g);
lb_add_member(m, name, g);
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2);
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
LLVMValueRef values[2] = {ptr, len};
res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
return res;
}
}
}
} else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) {
if (is_type_rune_array(type) && value.kind == ExactValue_String) {
i64 count = type->Array.count;
Type *elem = type->Array.elem;
LLVMTypeRef et = lb_type(m, elem);
Rune rune;
isize offset = 0;
isize width = 1;
String s = value.value_string;
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count);
for (i64 i = 0; i < count && offset < s.len; i++) {
width = utf8_decode(s.text+offset, s.len-offset, &rune);
offset += width;
elems[i] = LLVMConstInt(et, rune, true);
}
GB_ASSERT(offset == s.len);
res.value = llvm_const_array(et, elems, cast(unsigned)count);
return res;
}
GB_PANIC("This should not have happened!\n");
LLVMValueRef data = LLVMConstStringInContext(ctx,
cast(char const *)value.value_string.text,
cast(unsigned)value.value_string.len,
false /*DontNullTerminate*/);
res.value = data;
return res;
} else if (is_type_u8_array(type) && value.kind == ExactValue_String) {
GB_ASSERT(type->Array.count == value.value_string.len);
LLVMValueRef data = LLVMConstStringInContext(ctx,
cast(char const *)value.value_string.text,
cast(unsigned)value.value_string.len,
true /*DontNullTerminate*/);
res.value = data;
return res;
} else if (is_type_array(type) &&
value.kind != ExactValue_Invalid &&
value.kind != ExactValue_String &&
value.kind != ExactValue_Compound) {
i64 count = type->Array.count;
Type *elem = type->Array.elem;
lbValue single_elem = lb_const_value(m, elem, value, allow_local);
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count);
for (i64 i = 0; i < count; i++) {
elems[i] = single_elem.value;
}
res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count);
return res;
}
switch (value.kind) {
case ExactValue_Invalid:
res.value = LLVMConstNull(lb_type(m, original_type));
return res;
case ExactValue_Bool:
res.value = LLVMConstInt(lb_type(m, original_type), value.value_bool, false);
return res;
case ExactValue_String:
{
LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string);
lbValue res = {};
res.type = default_type(original_type);
if (is_type_cstring(res.type)) {
res.value = ptr;
} else {
if (value.value_string.len == 0) {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
}
LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true);
LLVMValueRef values[2] = {ptr, str_len};
GB_ASSERT(is_type_string(original_type));
res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
}
return res;
}
case ExactValue_Integer:
if (is_type_pointer(type)) {
LLVMTypeRef t = lb_type(m, original_type);
LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer);
res.value = LLVMConstIntToPtr(i, t);
} else {
res.value = lb_big_int_to_llvm(m, original_type, &value.value_integer);
}
return res;
case ExactValue_Float:
if (is_type_different_to_arch_endianness(type)) {
u64 u = bit_cast<u64>(value.value_float);
u = gb_endian_swap64(u);
res.value = LLVMConstReal(lb_type(m, original_type), bit_cast<f64>(u));
} else {
res.value = LLVMConstReal(lb_type(m, original_type), value.value_float);
}
return res;
case ExactValue_Complex:
{
LLVMValueRef values[2] = {};
switch (8*type_size_of(type)) {
case 32:
values[0] = lb_const_f16(m, cast(f32)value.value_complex->real);
values[1] = lb_const_f16(m, cast(f32)value.value_complex->imag);
break;
case 64:
values[0] = lb_const_f32(m, cast(f32)value.value_complex->real);
values[1] = lb_const_f32(m, cast(f32)value.value_complex->imag);
break;
case 128:
values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->real);
values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->imag);
break;
}
res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
return res;
}
break;
case ExactValue_Quaternion:
{
LLVMValueRef values[4] = {};
switch (8*type_size_of(type)) {
case 64:
// @QuaternionLayout
values[3] = lb_const_f16(m, cast(f32)value.value_quaternion->real);
values[0] = lb_const_f16(m, cast(f32)value.value_quaternion->imag);
values[1] = lb_const_f16(m, cast(f32)value.value_quaternion->jmag);
values[2] = lb_const_f16(m, cast(f32)value.value_quaternion->kmag);
break;
case 128:
// @QuaternionLayout
values[3] = lb_const_f32(m, cast(f32)value.value_quaternion->real);
values[0] = lb_const_f32(m, cast(f32)value.value_quaternion->imag);
values[1] = lb_const_f32(m, cast(f32)value.value_quaternion->jmag);
values[2] = lb_const_f32(m, cast(f32)value.value_quaternion->kmag);
break;
case 256:
// @QuaternionLayout
values[3] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->real);
values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->imag);
values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->jmag);
values[2] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->kmag);
break;
}
res.value = llvm_const_named_struct(lb_type(m, original_type), values, 4);
return res;
}
break;
case ExactValue_Pointer:
res.value = LLVMConstIntToPtr(LLVMConstInt(lb_type(m, t_uintptr), value.value_pointer, false), lb_type(m, original_type));
return res;
case ExactValue_Compound:
if (is_type_slice(type)) {
return lb_const_value(m, type, value, allow_local);
} else if (is_type_array(type)) {
ast_node(cl, CompoundLit, value.value_compound);
Type *elem_type = type->Array.elem;
isize elem_count = cl->elems.count;
if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
return lb_const_nil(m, original_type);
}
if (cl->elems[0]->kind == Ast_FieldValue) {
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
isize value_index = 0;
for (i64 i = 0; i < type->Array.count; i++) {
bool found = false;
for (isize j = 0; j < elem_count; j++) {
Ast *elem = cl->elems[j];
ast_node(fv, FieldValue, elem);
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;
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
found = true;
i += (hi-lo-1);
break;
}
} else {
TypeAndValue index_tav = fv->field->tav;
GB_ASSERT(index_tav.mode == Addressing_Constant);
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value;
values[value_index++] = val;
found = true;
break;
}
}
}
if (!found) {
values[value_index++] = LLVMConstNull(lb_type(m, elem_type));
}
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local);
return res;
} else {
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value;
}
for (isize i = elem_count; i < type->Array.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local);
return res;
}
} else if (is_type_enumerated_array(type)) {
ast_node(cl, CompoundLit, value.value_compound);
Type *elem_type = type->EnumeratedArray.elem;
isize elem_count = cl->elems.count;
if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
return lb_const_nil(m, original_type);
}
if (cl->elems[0]->kind == Ast_FieldValue) {
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count);
isize value_index = 0;
i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value);
i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value);
for (i64 i = total_lo; i <= total_hi; i++) {
bool found = false;
for (isize j = 0; j < elem_count; j++) {
Ast *elem = cl->elems[j];
ast_node(fv, FieldValue, elem);
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;
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
found = true;
i += (hi-lo-1);
break;
}
} else {
TypeAndValue index_tav = fv->field->tav;
GB_ASSERT(index_tav.mode == Addressing_Constant);
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value;
values[value_index++] = val;
found = true;
break;
}
}
}
if (!found) {
values[value_index++] = LLVMConstNull(lb_type(m, elem_type));
}
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local);
return res;
} else {
GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count);
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value;
}
for (isize i = elem_count; i < type->EnumeratedArray.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local);
return res;
}
} else if (is_type_simd_vector(type)) {
ast_node(cl, CompoundLit, value.value_compound);
Type *elem_type = type->SimdVector.elem;
isize elem_count = cl->elems.count;
if (elem_count == 0) {
return lb_const_nil(m, original_type);
}
GB_ASSERT(elem_type_can_be_constant(elem_type));
isize total_elem_count = cast(isize)type->SimdVector.count;
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, total_elem_count);
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value;
}
LLVMTypeRef et = lb_type(m, elem_type);
for (isize i = elem_count; i < type->SimdVector.count; i++) {
values[i] = LLVMConstNull(et);
}
for (isize i = 0; i < total_elem_count; i++) {
values[i] = llvm_const_cast(values[i], et);
}
res.value = LLVMConstVector(values, cast(unsigned)total_elem_count);
return res;
} else if (is_type_struct(type)) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
return lb_const_nil(m, original_type);
}
if (is_type_raw_union(type)) {
return lb_const_nil(m, original_type);
}
isize offset = 0;
if (type->Struct.custom_align > 0) {
offset = 1;
}
isize value_count = type->Struct.fields.count + offset;
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;
TypeAndValue tav = fv->value->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
Selection sel = lookup_field(type, name, false);
Entity *f = type->Struct.fields[sel.index[0]];
if (elem_type_can_be_constant(f->type)) {
values[offset+f->Variable.field_index] = lb_const_value(m, f->type, tav.value, allow_local).value;
visited[offset+f->Variable.field_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;
}
if (elem_type_can_be_constant(f->type)) {
values[offset+f->Variable.field_index] = lb_const_value(m, f->type, val, allow_local).value;
visited[offset+f->Variable.field_index] = true;
}
}
}
}
for (isize i = 0; i < type->Struct.fields.count; i++) {
if (!visited[offset+i]) {
GB_ASSERT(values[offset+i] == nullptr);
values[offset+i] = lb_const_nil(m, get_struct_field_type(type, i)).value;
}
}
if (type->Struct.custom_align > 0) {
values[0] = LLVMConstNull(lb_alignment_prefix_type_hack(m, type->Struct.custom_align));
}
bool is_constant = true;
for (isize i = 0; i < value_count; i++) {
LLVMValueRef val = values[i];
if (!LLVMIsConstant(val)) {
GB_ASSERT(is_local);
GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad);
is_constant = false;
}
}
if (is_constant) {
res.value = llvm_const_named_struct(lb_type(m, original_type), values, cast(unsigned)value_count);
return res;
} else {
// TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED
LLVMValueRef *old_values = values;
LLVMValueRef *new_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count);
for (isize i = 0; i < value_count; i++) {
LLVMValueRef old_value = old_values[i];
if (LLVMIsConstant(old_value)) {
new_values[i] = old_value;
} else {
new_values[i] = LLVMConstNull(LLVMTypeOf(old_value));
}
}
LLVMValueRef constant_value = llvm_const_named_struct(lb_type(m, original_type), new_values, cast(unsigned)value_count);
GB_ASSERT(is_local);
lbProcedure *p = m->curr_procedure;
lbAddr v = lb_add_local_generated(p, res.type, true);
LLVMBuildStore(p->builder, constant_value, v.addr.value);
for (isize i = 0; i < value_count; i++) {
LLVMValueRef val = old_values[i];
if (!LLVMIsConstant(val)) {
LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, "");
LLVMBuildStore(p->builder, val, dst);
}
}
return lb_addr_load(p, v);
}
} else if (is_type_bit_set(type)) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
return lb_const_nil(m, original_type);
}
i64 sz = type_size_of(type);
if (sz == 0) {
return lb_const_nil(m, original_type);
}
u64 bits = 0;
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 = type->BitSet.lower;
bits |= 1ull<<cast(u64)(v-lower);
}
if (is_type_different_to_arch_endianness(type)) {
i64 size = type_size_of(type);
switch (size) {
case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
}
}
res.value = LLVMConstInt(lb_type(m, original_type), bits, false);
return res;
} else {
return lb_const_nil(m, original_type);
}
break;
case ExactValue_Procedure:
{
Ast *expr = value.value_procedure;
GB_ASSERT(expr != nullptr);
if (expr->kind == Ast_ProcLit) {
return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
}
}
break;
case ExactValue_Typeid:
return lb_typeid(m, value.value_typeid);
}
return lb_const_nil(m, original_type);
}
+983
View File
@@ -0,0 +1,983 @@
LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
if (key == nullptr) {
return nullptr;
}
auto found = map_get(&m->debug_values, hash_pointer(key));
if (found) {
return *found;
}
return nullptr;
}
void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
if (key != nullptr) {
map_set(&m->debug_values, hash_pointer(key), value);
}
}
LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) {
if (node == nullptr) {
return nullptr;
}
return lb_get_llvm_metadata(m, node->file);
}
LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name));
for (isize i = p->scope_stack.count-1; i >= 0; i--) {
Scope *s = p->scope_stack[i];
LLVMMetadataRef md = lb_get_llvm_metadata(p->module, s);
if (md) {
return md;
}
}
return p->debug_info;
}
LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
LLVMMetadataRef scope = lb_get_current_debug_scope(p);
GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr);
}
LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
GB_ASSERT(node != nullptr);
return lb_debug_location_from_token_pos(p, ast_token(node).pos);
}
LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
Type *original_type = type;
LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size
GB_ASSERT(type != t_invalid);
unsigned const word_size = cast(unsigned)build_context.word_size;
unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
GB_ASSERT(type->kind == Type_Proc);
LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx);
unsigned parameter_count = 1;
for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind == Entity_Variable) {
parameter_count += 1;
}
}
LLVMMetadataRef *parameters = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, parameter_count);
unsigned param_index = 0;
if (type->Proc.result_count == 0) {
parameters[param_index++] = nullptr;
} else {
parameters[param_index++] = lb_debug_type(m, type->Proc.results);
}
LLVMMetadataRef parent_scope = nullptr;
LLVMMetadataRef scope = nullptr;
LLVMMetadataRef file = nullptr;
for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
parameters[param_index] = lb_debug_type(m, e->type);
param_index += 1;
}
LLVMDIFlags flags = LLVMDIFlagZero;
if (type->Proc.diverging) {
flags = LLVMDIFlagNoReturn;
}
return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags);
}
LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
unsigned field_line = 1;
LLVMDIFlags field_flags = LLVMDIFlagZero;
AstPackage *pkg = m->info->runtime_package;
GB_ASSERT(pkg->files.count != 0);
LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]);
LLVMMetadataRef scope = file;
return LLVMDIBuilderCreateMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line,
8*cast(u64)type_size_of(type), 8*cast(u32)type_align_of(type), offset_in_bits,
field_flags, lb_debug_type(m, type)
);
}
LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) {
AstPackage *pkg = m->info->runtime_package;
GB_ASSERT(pkg->files.count != 0);
LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]);
LLVMMetadataRef scope = file;
return LLVMDIBuilderCreateStructType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, 1, size_in_bits, align_in_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0);
}
LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) {
LLVMMetadataRef basic_type = LLVMDIBuilderCreateBasicType(m->debug_builder, cast(char const *)name.text, name.len, size_in_bits, encoding, flags);
#if 1
LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, basic_type, cast(char const *)name.text, name.len, nullptr, 0, nullptr, cast(u32)size_in_bits);
return final_decl;
#else
return basic_type;
#endif
}
LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
Type *original_type = type;
LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size
GB_ASSERT(type != t_invalid);
unsigned const word_size = cast(unsigned)build_context.word_size;
unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
switch (type->kind) {
case Type_Basic:
switch (type->Basic.kind) {
case Basic_llvm_bool: return lb_debug_type_basic_type(m, str_lit("llvm bool"), 1, LLVMDWARFTypeEncoding_Boolean);
case Basic_bool: return lb_debug_type_basic_type(m, str_lit("bool"), 8, LLVMDWARFTypeEncoding_Boolean);
case Basic_b8: return lb_debug_type_basic_type(m, str_lit("b8"), 8, LLVMDWARFTypeEncoding_Boolean);
case Basic_b16: return lb_debug_type_basic_type(m, str_lit("b16"), 16, LLVMDWARFTypeEncoding_Boolean);
case Basic_b32: return lb_debug_type_basic_type(m, str_lit("b32"), 32, LLVMDWARFTypeEncoding_Boolean);
case Basic_b64: return lb_debug_type_basic_type(m, str_lit("b64"), 64, LLVMDWARFTypeEncoding_Boolean);
case Basic_i8: return lb_debug_type_basic_type(m, str_lit("i8"), 8, LLVMDWARFTypeEncoding_Signed);
case Basic_u8: return lb_debug_type_basic_type(m, str_lit("u8"), 8, LLVMDWARFTypeEncoding_Unsigned);
case Basic_i16: return lb_debug_type_basic_type(m, str_lit("i16"), 16, LLVMDWARFTypeEncoding_Signed);
case Basic_u16: return lb_debug_type_basic_type(m, str_lit("u16"), 16, LLVMDWARFTypeEncoding_Unsigned);
case Basic_i32: return lb_debug_type_basic_type(m, str_lit("i32"), 32, LLVMDWARFTypeEncoding_Signed);
case Basic_u32: return lb_debug_type_basic_type(m, str_lit("u32"), 32, LLVMDWARFTypeEncoding_Unsigned);
case Basic_i64: return lb_debug_type_basic_type(m, str_lit("i64"), 64, LLVMDWARFTypeEncoding_Signed);
case Basic_u64: return lb_debug_type_basic_type(m, str_lit("u64"), 64, LLVMDWARFTypeEncoding_Unsigned);
case Basic_i128: return lb_debug_type_basic_type(m, str_lit("i128"), 128, LLVMDWARFTypeEncoding_Signed);
case Basic_u128: return lb_debug_type_basic_type(m, str_lit("u128"), 128, LLVMDWARFTypeEncoding_Unsigned);
case Basic_rune: return lb_debug_type_basic_type(m, str_lit("rune"), 32, LLVMDWARFTypeEncoding_Utf);
case Basic_f16: return lb_debug_type_basic_type(m, str_lit("f16"), 16, LLVMDWARFTypeEncoding_Float);
case Basic_f32: return lb_debug_type_basic_type(m, str_lit("f32"), 32, LLVMDWARFTypeEncoding_Float);
case Basic_f64: return lb_debug_type_basic_type(m, str_lit("f64"), 64, LLVMDWARFTypeEncoding_Float);
case Basic_int: return lb_debug_type_basic_type(m, str_lit("int"), word_bits, LLVMDWARFTypeEncoding_Signed);
case Basic_uint: return lb_debug_type_basic_type(m, str_lit("uint"), word_bits, LLVMDWARFTypeEncoding_Unsigned);
case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), word_bits, LLVMDWARFTypeEncoding_Unsigned);
case Basic_typeid:
return lb_debug_type_basic_type(m, str_lit("typeid"), word_bits, LLVMDWARFTypeEncoding_Unsigned);
// Endian Specific Types
case Basic_i16le: return lb_debug_type_basic_type(m, str_lit("i16le"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian);
case Basic_u16le: return lb_debug_type_basic_type(m, str_lit("u16le"), 16, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian);
case Basic_i32le: return lb_debug_type_basic_type(m, str_lit("i32le"), 32, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian);
case Basic_u32le: return lb_debug_type_basic_type(m, str_lit("u32le"), 32, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian);
case Basic_i64le: return lb_debug_type_basic_type(m, str_lit("i64le"), 64, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian);
case Basic_u64le: return lb_debug_type_basic_type(m, str_lit("u64le"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian);
case Basic_i128le: return lb_debug_type_basic_type(m, str_lit("i128le"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian);
case Basic_u128le: return lb_debug_type_basic_type(m, str_lit("u128le"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian);
case Basic_f16le: return lb_debug_type_basic_type(m, str_lit("f16le"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_f32le: return lb_debug_type_basic_type(m, str_lit("f32le"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_f64le: return lb_debug_type_basic_type(m, str_lit("f64le"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_i16be: return lb_debug_type_basic_type(m, str_lit("i16be"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian);
case Basic_u16be: return lb_debug_type_basic_type(m, str_lit("u16be"), 16, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian);
case Basic_i32be: return lb_debug_type_basic_type(m, str_lit("i32be"), 32, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian);
case Basic_u32be: return lb_debug_type_basic_type(m, str_lit("u32be"), 32, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian);
case Basic_i64be: return lb_debug_type_basic_type(m, str_lit("i64be"), 64, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian);
case Basic_u64be: return lb_debug_type_basic_type(m, str_lit("u64be"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian);
case Basic_i128be: return lb_debug_type_basic_type(m, str_lit("i128be"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian);
case Basic_u128be: return lb_debug_type_basic_type(m, str_lit("u128be"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian);
case Basic_f16be: return lb_debug_type_basic_type(m, str_lit("f16be"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_f32be: return lb_debug_type_basic_type(m, str_lit("f32be"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_f64be: return lb_debug_type_basic_type(m, str_lit("f64be"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
case Basic_complex32:
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0);
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 4);
return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements));
}
case Basic_complex64:
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0);
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 4);
return lb_debug_basic_struct(m, str_lit("complex64"), 64, 32, elements, gb_count_of(elements));
}
case Basic_complex128:
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0);
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 8);
return lb_debug_basic_struct(m, str_lit("complex128"), 128, 64, elements, gb_count_of(elements));
}
case Basic_quaternion64:
{
LLVMMetadataRef elements[4] = {};
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0);
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 4);
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 8);
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 12);
return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements));
}
case Basic_quaternion128:
{
LLVMMetadataRef elements[4] = {};
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0);
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 4);
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 8);
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 12);
return lb_debug_basic_struct(m, str_lit("quaternion128"), 128, 32, elements, gb_count_of(elements));
}
case Basic_quaternion256:
{
LLVMMetadataRef elements[4] = {};
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0);
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 8);
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 16);
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 24);
return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 32, elements, gb_count_of(elements));
}
case Basic_rawptr:
{
LLVMMetadataRef void_type = lb_debug_type_basic_type(m, str_lit("void"), 8, LLVMDWARFTypeEncoding_Unsigned);
return LLVMDIBuilderCreatePointerType(m->debug_builder, void_type, word_bits, word_bits, LLVMDWARFTypeEncoding_Address, "rawptr", 6);
}
case Basic_string:
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u8_ptr, 0);
elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, word_bits);
return lb_debug_basic_struct(m, str_lit("string"), 2*word_bits, word_bits, elements, gb_count_of(elements));
}
case Basic_cstring:
{
LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("char"), 8, LLVMDWARFTypeEncoding_Unsigned);
return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, word_bits, word_bits, 0, "cstring", 7);
}
case Basic_any:
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0);
elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, word_bits);
return lb_debug_basic_struct(m, str_lit("any"), 2*word_bits, word_bits, elements, gb_count_of(elements));
}
// Untyped types
case Basic_UntypedBool: GB_PANIC("Basic_UntypedBool"); break;
case Basic_UntypedInteger: GB_PANIC("Basic_UntypedInteger"); break;
case Basic_UntypedFloat: GB_PANIC("Basic_UntypedFloat"); break;
case Basic_UntypedComplex: GB_PANIC("Basic_UntypedComplex"); break;
case Basic_UntypedQuaternion: GB_PANIC("Basic_UntypedQuaternion"); break;
case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break;
case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break;
case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break;
case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break;
default: GB_PANIC("Basic Unhandled"); break;
}
break;
case Type_Named:
GB_PANIC("Type_Named should be handled in lb_debug_type separately");
case Type_Pointer:
return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), word_bits, word_bits, 0, nullptr, 0);
case Type_Array: {
LLVMMetadataRef subscripts[1] = {};
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
0ll,
type->Array.count
);
return LLVMDIBuilderCreateArrayType(m->debug_builder,
8*cast(uint64_t)type_size_of(type),
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->Array.elem),
subscripts, gb_count_of(subscripts));
}
case Type_EnumeratedArray: {
LLVMMetadataRef subscripts[1] = {};
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
0ll,
type->EnumeratedArray.count
);
LLVMMetadataRef array_type = LLVMDIBuilderCreateArrayType(m->debug_builder,
8*cast(uint64_t)type_size_of(type),
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->EnumeratedArray.elem),
subscripts, gb_count_of(subscripts));
gbString name = type_to_string(type, temporary_allocator());
return LLVMDIBuilderCreateTypedef(m->debug_builder, array_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
case Type_Struct:
case Type_Union:
case Type_Slice:
case Type_DynamicArray:
case Type_Map:
case Type_BitSet:
{
unsigned tag = DW_TAG_structure_type;
if (is_type_raw_union(type) || is_type_union(type)) {
tag = DW_TAG_union_type;
}
u64 size_in_bits = cast(u64)(8*type_size_of(type));
u32 align_in_bits = cast(u32)(8*type_size_of(type));
LLVMDIFlags flags = LLVMDIFlagZero;
LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType(
m->debug_builder, tag, "", 0, nullptr, nullptr, 0, 0, size_in_bits, align_in_bits, flags, "", 0
);
lbIncompleteDebugType idt = {};
idt.type = type;
idt.metadata = temp_forward_decl;
array_add(&m->debug_incomplete_types, idt);
lb_set_llvm_metadata(m, type, temp_forward_decl);
return temp_forward_decl;
}
case Type_Enum:
{
LLVMMetadataRef scope = nullptr;
LLVMMetadataRef file = nullptr;
unsigned line = 0;
unsigned element_count = cast(unsigned)type->Enum.fields.count;
LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
Type *bt = base_enum_type(type);
LLVMBool is_unsigned = is_type_unsigned(bt);
for (unsigned i = 0; i < element_count; i++) {
Entity *f = type->Enum.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
String name = f->token.string;
i64 value = exact_value_to_i64(f->Constant.value);
elements[i] = LLVMDIBuilderCreateEnumerator(m->debug_builder, cast(char const *)name.text, cast(size_t)name.len, value, is_unsigned);
}
LLVMMetadataRef class_type = lb_debug_type(m, bt);
return LLVMDIBuilderCreateEnumerationType(m->debug_builder, scope, "", 0, file, line, 8*type_size_of(type), 8*cast(unsigned)type_align_of(type), elements, element_count, class_type);
}
case Type_Tuple:
if (type->Tuple.variables.count == 1) {
return lb_debug_type(m, type->Tuple.variables[0]->type);
} else {
type_set_offsets(type);
LLVMMetadataRef parent_scope = nullptr;
LLVMMetadataRef scope = nullptr;
LLVMMetadataRef file = nullptr;
unsigned line = 0;
u64 size_in_bits = 8*cast(u64)type_size_of(type);
u32 align_in_bits = 8*cast(u32)type_align_of(type);
LLVMDIFlags flags = LLVMDIFlagZero;
unsigned element_count = cast(unsigned)type->Tuple.variables.count;
LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
for (unsigned i = 0; i < element_count; i++) {
Entity *f = type->Tuple.variables[i];
GB_ASSERT(f->kind == Entity_Variable);
String name = f->token.string;
unsigned field_line = 0;
LLVMDIFlags field_flags = LLVMDIFlagZero;
u64 offset_in_bits = 8*cast(u64)type->Tuple.offsets[i];
elements[i] = LLVMDIBuilderCreateMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line,
8*cast(u64)type_size_of(f->type), 8*cast(u32)type_align_of(f->type), offset_in_bits,
field_flags, lb_debug_type(m, f->type)
);
}
return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line,
size_in_bits, align_in_bits, flags,
nullptr, elements, element_count, 0, nullptr,
"", 0
);
}
case Type_Proc:
{
LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type);
LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, word_bits, word_bits, 0, nullptr, 0);
gbString name = type_to_string(type, temporary_allocator());
return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
break;
case Type_SimdVector:
return LLVMDIBuilderCreateVectorType(m->debug_builder, cast(unsigned)type->SimdVector.count, 8*cast(unsigned)type_align_of(type), lb_debug_type(m, type->SimdVector.elem), nullptr, 0);
case Type_RelativePointer: {
LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativePointer.base_integer);
gbString name = type_to_string(type, temporary_allocator());
return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
case Type_RelativeSlice:
{
unsigned element_count = 0;
LLVMMetadataRef elements[2] = {};
Type *base_integer = type->RelativeSlice.base_integer;
elements[0] = lb_debug_struct_field(m, str_lit("data_offset"), base_integer, 0);
elements[1] = lb_debug_struct_field(m, str_lit("len"), base_integer, 8*type_size_of(base_integer));
gbString name = type_to_string(type, temporary_allocator());
return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*word_bits, word_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0);
}
}
GB_PANIC("Invalid type %s", type_to_string(type));
return nullptr;
}
LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
LLVMMetadataRef found = nullptr;
for (;;) {
if (scope == nullptr) {
return nullptr;
}
if (scope->flags & ScopeFlag_Proc) {
found = lb_get_llvm_metadata(m, scope->procedure_entity);
if (found) {
return found;
}
}
if (scope->flags & ScopeFlag_File) {
found = lb_get_llvm_metadata(m, scope->file);
if (found) {
return found;
}
}
scope = scope->parent;
}
}
LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
GB_ASSERT(type != nullptr);
LLVMMetadataRef found = lb_get_llvm_metadata(m, type);
if (found != nullptr) {
return found;
}
if (type->kind == Type_Named) {
LLVMMetadataRef file = nullptr;
unsigned line = 0;
LLVMMetadataRef scope = nullptr;
if (type->Named.type_name != nullptr) {
Entity *e = type->Named.type_name;
scope = lb_get_base_scope_metadata(m, e->scope);
if (scope != nullptr) {
file = LLVMDIScopeGetFile(scope);
}
line = cast(unsigned)e->token.pos.line;
}
// TODO(bill): location data for Type_Named
u64 size_in_bits = 8*type_size_of(type);
u32 align_in_bits = 8*cast(u32)type_align_of(type);
String name = type->Named.name;
char const *name_text = cast(char const *)name.text;
size_t name_len = cast(size_t)name.len;
unsigned tag = DW_TAG_structure_type;
if (is_type_raw_union(type) || is_type_union(type)) {
tag = DW_TAG_union_type;
}
LLVMDIFlags flags = LLVMDIFlagZero;
Type *bt = base_type(type->Named.base);
lbIncompleteDebugType idt = {};
idt.type = type;
switch (bt->kind) {
case Type_Enum:
{
unsigned line = 0;
unsigned element_count = cast(unsigned)bt->Enum.fields.count;
LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
Type *ct = base_enum_type(type);
LLVMBool is_unsigned = is_type_unsigned(ct);
for (unsigned i = 0; i < element_count; i++) {
Entity *f = bt->Enum.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
String name = f->token.string;
i64 value = exact_value_to_i64(f->Constant.value);
elements[i] = LLVMDIBuilderCreateEnumerator(m->debug_builder, cast(char const *)name.text, cast(size_t)name.len, value, is_unsigned);
}
LLVMMetadataRef class_type = lb_debug_type(m, ct);
return LLVMDIBuilderCreateEnumerationType(m->debug_builder, scope, name_text, name_len, file, line, 8*type_size_of(type), 8*cast(unsigned)type_align_of(type), elements, element_count, class_type);
}
case Type_Basic:
case Type_Pointer:
case Type_Array:
case Type_EnumeratedArray:
case Type_Tuple:
case Type_Proc:
case Type_SimdVector:
case Type_RelativePointer:
case Type_RelativeSlice:
{
LLVMMetadataRef debug_bt = lb_debug_type(m, bt);
LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, debug_bt, name_text, name_len, file, line, scope, align_in_bits);
lb_set_llvm_metadata(m, type, final_decl);
return final_decl;
}
case Type_Slice:
case Type_DynamicArray:
case Type_Map:
case Type_Struct:
case Type_Union:
case Type_BitSet:
LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType(
m->debug_builder, tag, name_text, name_len, nullptr, nullptr, 0, 0, size_in_bits, align_in_bits, flags, "", 0
);
idt.metadata = temp_forward_decl;
array_add(&m->debug_incomplete_types, idt);
lb_set_llvm_metadata(m, type, temp_forward_decl);
return temp_forward_decl;
}
}
LLVMMetadataRef dt = lb_debug_type_internal(m, type);
lb_set_llvm_metadata(m, type, dt);
return dt;
}
void lb_debug_complete_types(lbModule *m) {
unsigned const word_size = cast(unsigned)build_context.word_size;
unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
GB_ASSERT(idt.type != nullptr);
GB_ASSERT(idt.metadata != nullptr);
Type *t = idt.type;
Type *bt = base_type(t);
LLVMMetadataRef parent_scope = nullptr;
LLVMMetadataRef file = nullptr;
unsigned line_number = 0;
u64 size_in_bits = 8*type_size_of(t);
u32 align_in_bits = cast(u32)(8*type_align_of(t));
LLVMDIFlags flags = LLVMDIFlagZero;
LLVMMetadataRef derived_from = nullptr;
LLVMMetadataRef *elements = nullptr;
unsigned element_count = 0;
unsigned runtime_lang = 0; // Objective-C runtime version
char const *unique_id = "";
LLVMMetadataRef vtable_holder = nullptr;
size_t unique_id_len = 0;
LLVMMetadataRef record_scope = nullptr;
switch (bt->kind) {
case Type_Slice:
case Type_DynamicArray:
case Type_Map:
case Type_Struct:
case Type_Union:
case Type_BitSet: {
bool is_union = is_type_raw_union(bt) || is_type_union(bt);
String name = str_lit("<anonymous-struct>");
if (t->kind == Type_Named) {
name = t->Named.name;
if (t->Named.type_name && t->Named.type_name->pkg && t->Named.type_name->pkg->name.len != 0) {
name = concatenate3_strings(temporary_allocator(), t->Named.type_name->pkg->name, str_lit("."), t->Named.name);
}
LLVMMetadataRef file = nullptr;
unsigned line = 0;
LLVMMetadataRef file_scope = nullptr;
if (t->Named.type_name != nullptr) {
Entity *e = t->Named.type_name;
file_scope = lb_get_llvm_metadata(m, e->scope);
if (file_scope != nullptr) {
file = LLVMDIScopeGetFile(file_scope);
}
line = cast(unsigned)e->token.pos.line;
}
// TODO(bill): location data for Type_Named
} else {
name = make_string_c(type_to_string(t, temporary_allocator()));
}
switch (bt->kind) {
case Type_Slice:
element_count = 2;
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->Slice.elem), 0*word_bits);
elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, 1*word_bits);
break;
case Type_DynamicArray:
element_count = 4;
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->DynamicArray.elem), 0*word_bits);
elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, 1*word_bits);
elements[2] = lb_debug_struct_field(m, str_lit("cap"), t_int, 2*word_bits);
elements[3] = lb_debug_struct_field(m, str_lit("allocator"), t_allocator, 3*word_bits);
break;
case Type_Map:
bt = bt->Map.internal_type;
/*fallthrough*/
case Type_Struct:
if (file == nullptr) {
if (bt->Struct.node) {
file = lb_get_llvm_metadata(m, bt->Struct.node->file);
line_number = cast(unsigned)ast_token(bt->Struct.node).pos.line;
}
}
type_set_offsets(bt);
{
isize element_offset = 0;
record_scope = lb_get_llvm_metadata(m, bt->Struct.scope);
switch (bt->Struct.soa_kind) {
case StructSoa_Slice: element_offset = 1; break;
case StructSoa_Dynamic: element_offset = 3; break;
}
element_count = cast(unsigned)(bt->Struct.fields.count + element_offset);
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
switch (bt->Struct.soa_kind) {
case StructSoa_Slice:
elements[0] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
".len", 4,
file, 0,
8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
8*type_size_of(bt)-word_bits,
LLVMDIFlagZero, lb_debug_type(m, t_int)
);
break;
case StructSoa_Dynamic:
elements[0] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
".len", 4,
file, 0,
8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
8*type_size_of(bt)-word_bits + 0*word_bits,
LLVMDIFlagZero, lb_debug_type(m, t_int)
);
elements[1] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
".cap", 4,
file, 0,
8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
8*type_size_of(bt)-word_bits + 1*word_bits,
LLVMDIFlagZero, lb_debug_type(m, t_int)
);
elements[2] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
".allocator", 12,
file, 0,
8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
8*type_size_of(bt)-word_bits + 2*word_bits,
LLVMDIFlagZero, lb_debug_type(m, t_allocator)
);
break;
}
for_array(j, bt->Struct.fields) {
Entity *f = bt->Struct.fields[j];
String fname = f->token.string;
unsigned field_line = 0;
LLVMDIFlags field_flags = LLVMDIFlagZero;
u64 offset_in_bits = 8*cast(u64)bt->Struct.offsets[j];
elements[element_offset+j] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
cast(char const *)fname.text, cast(size_t)fname.len,
file, field_line,
8*cast(u64)type_size_of(f->type), 8*cast(u32)type_align_of(f->type),
offset_in_bits,
field_flags, lb_debug_type(m, f->type)
);
}
}
break;
case Type_Union:
{
if (file == nullptr) {
GB_ASSERT(bt->Union.node != nullptr);
file = lb_get_llvm_metadata(m, bt->Union.node->file);
line_number = cast(unsigned)ast_token(bt->Union.node).pos.line;
}
isize index_offset = 1;
if (is_type_union_maybe_pointer(bt)) {
index_offset = 0;
}
record_scope = lb_get_llvm_metadata(m, bt->Union.scope);
element_count = cast(unsigned)bt->Union.variants.count;
if (index_offset > 0) {
element_count += 1;
}
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
if (index_offset > 0) {
Type *tag_type = union_tag_type(bt);
unsigned field_line = 0;
u64 offset_in_bits = 8*cast(u64)bt->Union.variant_block_size;
LLVMDIFlags field_flags = LLVMDIFlagZero;
elements[0] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
"tag", 3,
file, field_line,
8*cast(u64)type_size_of(tag_type), 8*cast(u32)type_align_of(tag_type),
offset_in_bits,
field_flags, lb_debug_type(m, tag_type)
);
}
for_array(j, bt->Union.variants) {
Type *variant = bt->Union.variants[j];
unsigned field_index = cast(unsigned)(index_offset+j);
char name[16] = {};
gb_snprintf(name, gb_size_of(name), "v%u", field_index);
isize name_len = gb_strlen(name);
unsigned field_line = 0;
LLVMDIFlags field_flags = LLVMDIFlagZero;
u64 offset_in_bits = 0;
elements[field_index] = LLVMDIBuilderCreateMemberType(
m->debug_builder, record_scope,
name, name_len,
file, field_line,
8*cast(u64)type_size_of(variant), 8*cast(u32)type_align_of(variant),
offset_in_bits,
field_flags, lb_debug_type(m, variant)
);
}
}
break;
case Type_BitSet:
{
if (file == nullptr) {
GB_ASSERT(bt->BitSet.node != nullptr);
file = lb_get_llvm_metadata(m, bt->BitSet.node->file);
line_number = cast(unsigned)ast_token(bt->BitSet.node).pos.line;
}
LLVMMetadataRef bit_set_field_type = lb_debug_type(m, t_bool);
LLVMMetadataRef scope = file;
Type *elem = base_type(bt->BitSet.elem);
if (elem->kind == Type_Enum) {
element_count = cast(unsigned)elem->Enum.fields.count;
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
for_array(i, elem->Enum.fields) {
Entity *f = elem->Enum.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
i64 val = exact_value_to_i64(f->Constant.value);
String name = f->token.string;
u64 offset_in_bits = cast(u64)(val - bt->BitSet.lower);
elements[i] = LLVMDIBuilderCreateBitFieldMemberType(
m->debug_builder,
scope,
cast(char const *)name.text, name.len,
file, line_number,
1,
offset_in_bits,
0,
LLVMDIFlagZero,
bit_set_field_type
);
}
} else {
char name[32] = {};
GB_ASSERT(is_type_integer(elem));
i64 count = bt->BitSet.upper - bt->BitSet.lower + 1;
GB_ASSERT(0 <= count);
element_count = cast(unsigned)count;
elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
for (unsigned i = 0; i < element_count; i++) {
u64 offset_in_bits = i;
i64 val = bt->BitSet.lower + cast(i64)i;
gb_snprintf(name, gb_count_of(name), "%lld", cast(long long)val);
elements[i] = LLVMDIBuilderCreateBitFieldMemberType(
m->debug_builder,
scope,
name, gb_strlen(name),
file, line_number,
1,
offset_in_bits,
0,
LLVMDIFlagZero,
bit_set_field_type
);
}
}
}
}
LLVMMetadataRef final_metadata = nullptr;
if (is_union) {
final_metadata = LLVMDIBuilderCreateUnionType(
m->debug_builder,
parent_scope,
cast(char const *)name.text, cast(size_t)name.len,
file, line_number,
size_in_bits, align_in_bits,
flags,
elements, element_count,
runtime_lang,
unique_id, unique_id_len
);
} else {
final_metadata = LLVMDIBuilderCreateStructType(
m->debug_builder,
parent_scope,
cast(char const *)name.text, cast(size_t)name.len,
file, line_number,
size_in_bits, align_in_bits,
flags,
derived_from,
elements, element_count,
runtime_lang,
vtable_holder,
unique_id, unique_id_len
);
}
LLVMMetadataReplaceAllUsesWith(idt.metadata, final_metadata);
lb_set_llvm_metadata(m, idt.type, final_metadata);
} break;
default:
GB_PANIC("invalid incomplete debug type");
break;
}
}
array_clear(&m->debug_incomplete_types);
}
void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) {
if (p->debug_info == nullptr) {
return;
}
if (type == nullptr) {
return;
}
if (type == t_invalid) {
return;
}
if (p->body == nullptr) {
return;
}
lbModule *m = p->module;
String const &name = token.string;
if (name == "" || name == "_") {
return;
}
if (lb_get_llvm_metadata(m, ptr) != nullptr) {
// Already been set
return;
}
AstFile *file = p->body->file;
LLVMMetadataRef llvm_scope = lb_get_current_debug_scope(p);
LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file);
GB_ASSERT(llvm_scope != nullptr);
if (llvm_file == nullptr) {
llvm_file = LLVMDIScopeGetFile(llvm_scope);
}
if (llvm_file == nullptr) {
return;
}
unsigned alignment_in_bits = cast(unsigned)(8*type_align_of(type));
LLVMDIFlags flags = LLVMDIFlagZero;
LLVMBool always_preserve = build_context.optimization_level == 0;
LLVMMetadataRef debug_type = lb_debug_type(m, type);
LLVMMetadataRef var_info = LLVMDIBuilderCreateAutoVariable(
m->debug_builder, llvm_scope,
cast(char const *)name.text, cast(size_t)name.len,
llvm_file, token.pos.line,
debug_type,
always_preserve, flags, alignment_in_bits
);
LLVMValueRef storage = ptr;
LLVMValueRef instr = ptr;
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos);
LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0);
lb_set_llvm_metadata(m, ptr, llvm_expr);
LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr);
}
void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
if (!p->debug_info || !p->body) {
return;
}
LLVMMetadataRef loc = LLVMGetCurrentDebugLocation2(p->builder);
if (!loc) {
return;
}
TokenPos pos = {};
pos.file_id = p->body->file ? p->body->file->id : 0;
pos.line = LLVMDILocationGetLine(loc);
pos.column = LLVMDILocationGetColumn(loc);
Token token = {};
token.kind = Token_context;
token.string = str_lit("context");
token.pos = pos;
lb_add_debug_local_variable(p, ctx.addr.value, t_context, token);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+855
View File
@@ -0,0 +1,855 @@
isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
isize index = type_info_index(info, type, false);
if (index >= 0) {
auto *set = &info->minimum_dependency_type_info_set;
for_array(i, set->entries) {
if (set->entries[i].ptr == index) {
return i+1;
}
}
}
if (err_on_not_found) {
GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index);
}
return -1;
}
lbValue lb_typeid(lbModule *m, Type *type) {
type = default_type(type);
u64 id = cast(u64)lb_type_info_index(m->info, type);
GB_ASSERT(id >= 0);
u64 kind = Typeid_Invalid;
u64 named = is_type_named(type) && type->kind != Type_Basic;
u64 special = 0;
u64 reserved = 0;
Type *bt = base_type(type);
TypeKind tk = bt->kind;
switch (tk) {
case Type_Basic: {
u32 flags = bt->Basic.flags;
if (flags & BasicFlag_Boolean) kind = Typeid_Boolean;
if (flags & BasicFlag_Integer) kind = Typeid_Integer;
if (flags & BasicFlag_Unsigned) kind = Typeid_Integer;
if (flags & BasicFlag_Float) kind = Typeid_Float;
if (flags & BasicFlag_Complex) kind = Typeid_Complex;
if (flags & BasicFlag_Pointer) kind = Typeid_Pointer;
if (flags & BasicFlag_String) kind = Typeid_String;
if (flags & BasicFlag_Rune) kind = Typeid_Rune;
} break;
case Type_Pointer: kind = Typeid_Pointer; break;
case Type_Array: kind = Typeid_Array; break;
case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break;
case Type_Slice: kind = Typeid_Slice; break;
case Type_DynamicArray: kind = Typeid_Dynamic_Array; break;
case Type_Map: kind = Typeid_Map; break;
case Type_Struct: kind = Typeid_Struct; break;
case Type_Enum: kind = Typeid_Enum; break;
case Type_Union: kind = Typeid_Union; break;
case Type_Tuple: kind = Typeid_Tuple; break;
case Type_Proc: kind = Typeid_Procedure; break;
case Type_BitSet: kind = Typeid_Bit_Set; break;
case Type_SimdVector: kind = Typeid_Simd_Vector; break;
case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
case Type_RelativeSlice: kind = Typeid_Relative_Slice; break;
}
if (is_type_cstring(type)) {
special = 1;
} else if (is_type_integer(type) && !is_type_unsigned(type)) {
special = 1;
}
u64 data = 0;
if (build_context.word_size == 4) {
GB_ASSERT(id <= (1u<<24u));
data |= (id &~ (1u<<24)) << 0u; // index
data |= (kind &~ (1u<<5)) << 24u; // kind
data |= (named &~ (1u<<1)) << 29u; // kind
data |= (special &~ (1u<<1)) << 30u; // kind
data |= (reserved &~ (1u<<1)) << 31u; // kind
} else {
GB_ASSERT(build_context.word_size == 8);
GB_ASSERT(id <= (1ull<<56u));
data |= (id &~ (1ull<<56)) << 0ul; // index
data |= (kind &~ (1ull<<5)) << 56ull; // kind
data |= (named &~ (1ull<<1)) << 61ull; // kind
data |= (special &~ (1ull<<1)) << 62ull; // kind
data |= (reserved &~ (1ull<<1)) << 63ull; // kind
}
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, t_typeid), data, false);
res.type = t_typeid;
return res;
}
lbValue lb_type_info(lbModule *m, Type *type) {
type = default_type(type);
isize index = lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
LLVMTypeRef it = lb_type(m, t_int);
LLVMValueRef indices[2] = {
LLVMConstInt(it, 0, false),
LLVMConstInt(it, index, true),
};
lbValue value = {};
value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
value.type = t_type_info_ptr;
return value;
}
lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
i32 index = cast(i32)lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
// gb_printf_err("%d %s\n", index, type_to_string(type));
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(m, t_int), 0, false),
LLVMConstInt(lb_type(m, t_int), index, false),
};
lbValue res = {};
res.type = t_type_info_ptr;
res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices));
return res;
}
lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index);
lb_global_type_info_member_types_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_names.addr, lb_global_type_info_member_names_index);
lb_global_type_info_member_names_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_offsets.addr, lb_global_type_info_member_offsets_index);
lb_global_type_info_member_offsets_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_usings.addr, lb_global_type_info_member_usings_index);
lb_global_type_info_member_usings_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_tags.addr, lb_global_type_info_member_tags_index);
lb_global_type_info_member_tags_index += cast(i32)count;
return offset;
}
void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
lbModule *m = p->module;
LLVMContextRef ctx = m->ctx;
CheckerInfo *info = m->info;
{
// NOTE(bill): Set the type_table slice with the global backing array
lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table"));
Type *type = base_type(lb_global_type_info_data_entity->type);
GB_ASSERT(is_type_array(type));
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef values[2] = {
LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
};
LLVMValueRef slice = llvm_const_named_struct(llvm_addr_type(global_type_table), values, gb_count_of(values));
LLVMSetInitializer(global_type_table.value, slice);
}
// Useful types
Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64));
Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string));
Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags"));
Type *t_type_info_flags = type_info_flags_entity->type;
i32 type_info_member_types_index = 0;
i32 type_info_member_names_index = 0;
i32 type_info_member_offsets_index = 0;
for_array(type_info_type_index, info->type_info_types) {
Type *t = info->type_info_types[type_info_type_index];
if (t == nullptr || t == t_invalid) {
continue;
}
isize entry_index = lb_type_info_index(info, t, false);
if (entry_index <= 0) {
continue;
}
lbValue tag = {};
lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data_ptr(m), cast(i32)entry_index);
lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4);
lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t));
lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t)));
lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t)));
lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), type_info_flags);
lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 3), lb_typeid(m, t));
switch (t->kind) {
case Type_Named: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr);
LLVMValueRef pkg_name = nullptr;
if (t->Named.type_name->pkg) {
pkg_name = lb_const_string(m, t->Named.type_name->pkg->name).value;
} else {
pkg_name = LLVMConstNull(lb_type(m, t_string));
}
String proc_name = {};
if (t->Named.type_name->parent_proc_decl) {
DeclInfo *decl = t->Named.type_name->parent_proc_decl;
if (decl->entity && decl->entity->kind == Entity_Procedure) {
proc_name = decl->entity->token.string;
}
}
TokenPos pos = t->Named.type_name->token.pos;
lbValue loc = lb_emit_source_code_location(p, proc_name, pos);
LLVMValueRef vals[4] = {
lb_const_string(p->module, t->Named.type_name->token.string).value,
lb_get_type_info_ptr(m, t->Named.base).value,
pkg_name,
loc.value
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Basic:
switch (t->Basic.kind) {
case Basic_bool:
case Basic_b8:
case Basic_b16:
case Basic_b32:
case Basic_b64:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_boolean_ptr);
break;
case Basic_i8:
case Basic_u8:
case Basic_i16:
case Basic_u16:
case Basic_i32:
case Basic_u32:
case Basic_i64:
case Basic_u64:
case Basic_i128:
case Basic_u128:
case Basic_i16le:
case Basic_u16le:
case Basic_i32le:
case Basic_u32le:
case Basic_i64le:
case Basic_u64le:
case Basic_i128le:
case Basic_u128le:
case Basic_i16be:
case Basic_u16be:
case Basic_i32be:
case Basic_u32be:
case Basic_i64be:
case Basic_u64be:
case Basic_i128be:
case Basic_u128be:
case Basic_int:
case Basic_uint:
case Basic_uintptr: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_integer_ptr);
lbValue is_signed = lb_const_bool(m, t_bool, (t->Basic.flags & BasicFlag_Unsigned) == 0);
// NOTE(bill): This is matches the runtime layout
u8 endianness_value = 0;
if (t->Basic.flags & BasicFlag_EndianLittle) {
endianness_value = 1;
} else if (t->Basic.flags & BasicFlag_EndianBig) {
endianness_value = 2;
}
lbValue endianness = lb_const_int(m, t_u8, endianness_value);
LLVMValueRef vals[2] = {
is_signed.value,
endianness.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Basic_rune:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_rune_ptr);
break;
case Basic_f16:
case Basic_f32:
case Basic_f64:
case Basic_f16le:
case Basic_f32le:
case Basic_f64le:
case Basic_f16be:
case Basic_f32be:
case Basic_f64be:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_float_ptr);
// NOTE(bill): This is matches the runtime layout
u8 endianness_value = 0;
if (t->Basic.flags & BasicFlag_EndianLittle) {
endianness_value = 1;
} else if (t->Basic.flags & BasicFlag_EndianBig) {
endianness_value = 2;
}
lbValue endianness = lb_const_int(m, t_u8, endianness_value);
LLVMValueRef vals[1] = {
endianness.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Basic_complex32:
case Basic_complex64:
case Basic_complex128:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_complex_ptr);
break;
case Basic_quaternion64:
case Basic_quaternion128:
case Basic_quaternion256:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_quaternion_ptr);
break;
case Basic_rawptr:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr);
break;
case Basic_string:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr);
break;
case Basic_cstring:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr);
LLVMValueRef vals[1] = {
lb_const_bool(m, t_bool, true).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Basic_any:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_any_ptr);
break;
case Basic_typeid:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_typeid_ptr);
break;
}
break;
case Type_Pointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem);
LLVMValueRef vals[1] = {
gep.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Array: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr);
i64 ez = type_size_of(t->Array.elem);
LLVMValueRef vals[3] = {
lb_get_type_info_ptr(m, t->Array.elem).value,
lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, t->Array.count).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_EnumeratedArray: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr);
LLVMValueRef vals[6] = {
lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value,
lb_get_type_info_ptr(m, t->EnumeratedArray.index).value,
lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value,
lb_const_int(m, t_int, t->EnumeratedArray.count).value,
// Unions
LLVMConstNull(lb_type(m, t_type_info_enum_value)),
LLVMConstNull(lb_type(m, t_type_info_enum_value)),
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
// NOTE(bill): Union assignment
lbValue min_value = lb_emit_struct_ep(p, tag, 4);
lbValue max_value = lb_emit_struct_ep(p, tag, 5);
lbValue min_v = lb_const_value(m, t_i64, t->EnumeratedArray.min_value);
lbValue max_v = lb_const_value(m, t_i64, t->EnumeratedArray.max_value);
lb_emit_store(p, min_value, min_v);
lb_emit_store(p, max_value, max_v);
break;
}
case Type_DynamicArray: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->DynamicArray.elem).value,
lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Slice: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->Slice.elem).value,
lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Proc: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_procedure_ptr);
LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr));
LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr));
if (t->Proc.params != nullptr) {
params = lb_get_type_info_ptr(m, t->Proc.params).value;
}
if (t->Proc.results != nullptr) {
results = lb_get_type_info_ptr(m, t->Proc.results).value;
}
LLVMValueRef vals[4] = {
params,
results,
lb_const_bool(m, t_bool, t->Proc.variadic).value,
lb_const_int(m, t_u8, t->Proc.calling_convention).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Tuple: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_tuple_ptr);
lbValue memory_types = lb_type_info_member_types_offset(p, t->Tuple.variables.count);
lbValue memory_names = lb_type_info_member_names_offset(p, t->Tuple.variables.count);
for_array(i, t->Tuple.variables) {
// NOTE(bill): offset is not used for tuples
Entity *f = t->Tuple.variables[i];
lbValue index = lb_const_int(m, t_int, i);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
// TODO(bill): Make this constant if possible, 'lb_const_store' does not work
lb_emit_store(p, type_info, lb_type_info(m, f->type));
if (f->token.string.len > 0) {
lbValue name = lb_emit_ptr_offset(p, memory_names, index);
lb_emit_store(p, name, lb_const_string(m, f->token.string));
}
}
lbValue count = lb_const_int(m, t_int, t->Tuple.variables.count);
LLVMValueRef types_slice = llvm_const_slice(m, memory_types, count);
LLVMValueRef names_slice = llvm_const_slice(m, memory_names, count);
LLVMValueRef vals[2] = {
types_slice,
names_slice,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Enum:
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enum_ptr);
{
GB_ASSERT(t->Enum.base_type != nullptr);
// GB_ASSERT_MSG(type_size_of(t_type_info_enum_value) == 16, "%lld == 16", cast(long long)type_size_of(t_type_info_enum_value));
LLVMValueRef vals[3] = {};
vals[0] = lb_type_info(m, t->Enum.base_type).value;
if (t->Enum.fields.count > 0) {
auto fields = t->Enum.fields;
lbValue name_array = lb_generate_global_array(m, t_string, fields.count,
str_lit("$enum_names"), cast(i64)entry_index);
lbValue value_array = lb_generate_global_array(m, t_type_info_enum_value, fields.count,
str_lit("$enum_values"), cast(i64)entry_index);
LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count);
LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count);
GB_ASSERT(is_type_integer(t->Enum.base_type));
LLVMTypeRef align_type = lb_alignment_prefix_type_hack(m, type_align_of(t));
LLVMTypeRef array_type = LLVMArrayType(lb_type(m, t_u8), 8);
for_array(i, fields) {
name_values[i] = lb_const_string(m, fields[i]->token.string).value;
value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value;
}
LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_values, cast(unsigned)fields.count);
LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
LLVMSetInitializer(name_array.value, name_init);
LLVMSetInitializer(value_array.value, value_init);
lbValue v_count = lb_const_int(m, t_int, fields.count);
vals[1] = llvm_const_slice(m, lb_array_elem(p, name_array), v_count);
vals[2] = llvm_const_slice(m, lb_array_elem(p, value_array), v_count);
} else {
vals[1] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[1]->type));
vals[2] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[2]->type));
}
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Type_Union: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_union_ptr);
{
LLVMValueRef vals[7] = {};
isize variant_count = gb_max(0, t->Union.variants.count);
lbValue memory_types = lb_type_info_member_types_offset(p, variant_count);
// NOTE(bill): Zeroth is nil so ignore it
for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
Type *vt = t->Union.variants[variant_index];
lbValue tip = lb_get_type_info_ptr(m, vt);
lbValue index = lb_const_int(m, t_int, variant_index);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
lb_emit_store(p, type_info, lb_type_info(m, vt));
}
lbValue count = lb_const_int(m, t_int, variant_count);
vals[0] = llvm_const_slice(m, memory_types, count);
i64 tag_size = union_tag_size(t);
i64 tag_offset = align_formula(t->Union.variant_block_size, tag_size);
if (tag_size > 0) {
vals[1] = lb_const_int(m, t_uintptr, tag_offset).value;
vals[2] = lb_type_info(m, union_tag_type(t)).value;
} else {
vals[1] = lb_const_int(m, t_uintptr, 0).value;
vals[2] = LLVMConstNull(lb_type(m, t_type_info_ptr));
}
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
vals[3] = lb_get_equal_proc_for_type(m, t).value;
}
vals[4] = lb_const_bool(m, t_bool, t->Union.custom_align != 0).value;
vals[5] = lb_const_bool(m, t_bool, t->Union.no_nil).value;
vals[6] = lb_const_bool(m, t_bool, t->Union.maybe).value;
for (isize i = 0; i < gb_count_of(vals); i++) {
if (vals[i] == nullptr) {
vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i)));
}
}
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
}
case Type_Struct: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr);
LLVMValueRef vals[12] = {};
{
lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed);
lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union);
lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0);
vals[5] = is_packed.value;
vals[6] = is_raw_union.value;
vals[7] = is_custom_align.value;
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
vals[8] = lb_get_equal_proc_for_type(m, t).value;
}
if (t->Struct.soa_kind != StructSoa_None) {
lbValue kind = lb_emit_struct_ep(p, tag, 9);
Type *kind_type = type_deref(kind.type);
lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind));
lbValue soa_type = lb_type_info(m, t->Struct.soa_elem);
lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count);
vals[9] = soa_kind.value;
vals[10] = soa_type.value;
vals[11] = soa_len.value;
}
}
isize count = t->Struct.fields.count;
if (count > 0) {
lbValue memory_types = lb_type_info_member_types_offset (p, count);
lbValue memory_names = lb_type_info_member_names_offset (p, count);
lbValue memory_offsets = lb_type_info_member_offsets_offset(p, count);
lbValue memory_usings = lb_type_info_member_usings_offset (p, count);
lbValue memory_tags = lb_type_info_member_tags_offset (p, count);
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
for (isize source_index = 0; source_index < count; source_index++) {
// TODO(bill): Order fields in source order not layout order
Entity *f = t->Struct.fields[source_index];
lbValue tip = lb_get_type_info_ptr(m, f->type);
i64 foffset = 0;
if (!t->Struct.is_raw_union) {
foffset = t->Struct.offsets[f->Variable.field_index];
}
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
lbValue index = lb_const_int(m, t_int, source_index);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
lbValue offset = lb_emit_ptr_offset(p, memory_offsets, index);
lbValue is_using = lb_emit_ptr_offset(p, memory_usings, index);
lb_emit_store(p, type_info, lb_type_info(m, f->type));
if (f->token.string.len > 0) {
lbValue name = lb_emit_ptr_offset(p, memory_names, index);
lb_emit_store(p, name, lb_const_string(m, f->token.string));
}
lb_emit_store(p, offset, lb_const_int(m, t_uintptr, foffset));
lb_emit_store(p, is_using, lb_const_bool(m, t_bool, (f->flags&EntityFlag_Using) != 0));
if (t->Struct.tags.count > 0) {
String tag_string = t->Struct.tags[source_index];
if (tag_string.len > 0) {
lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index);
lb_emit_store(p, tag_ptr, lb_const_string(m, tag_string));
}
}
}
lbValue cv = lb_const_int(m, t_int, count);
vals[0] = llvm_const_slice(m, memory_types, cv);
vals[1] = llvm_const_slice(m, memory_names, cv);
vals[2] = llvm_const_slice(m, memory_offsets, cv);
vals[3] = llvm_const_slice(m, memory_usings, cv);
vals[4] = llvm_const_slice(m, memory_tags, cv);
}
for (isize i = 0; i < gb_count_of(vals); i++) {
if (vals[i] == nullptr) {
vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i)));
}
}
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Map: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
init_map_internal_types(t);
LLVMValueRef vals[5] = {
lb_get_type_info_ptr(m, t->Map.key).value,
lb_get_type_info_ptr(m, t->Map.value).value,
lb_get_type_info_ptr(m, t->Map.generated_struct_type).value,
lb_get_equal_proc_for_type(m, t->Map.key).value,
lb_get_hasher_proc_for_type(m, t->Map.key).value
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_BitSet:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_set_ptr);
GB_ASSERT(is_type_typed(t->BitSet.elem));
LLVMValueRef vals[4] = {
lb_get_type_info_ptr(m, t->BitSet.elem).value,
LLVMConstNull(lb_type(m, t_type_info_ptr)),
lb_const_int(m, t_i64, t->BitSet.lower).value,
lb_const_int(m, t_i64, t->BitSet.upper).value,
};
if (t->BitSet.underlying != nullptr) {
vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value;
}
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Type_SimdVector:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_simd_vector_ptr);
LLVMValueRef vals[3] = {};
vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value;
vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Type_RelativePointer:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value,
lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
case Type_RelativeSlice:
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value,
lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
}
break;
}
if (tag.value != nullptr) {
Type *tag_type = type_deref(tag.type);
GB_ASSERT(is_type_named(tag_type));
// lb_emit_store_union_variant(p, variant_ptr, lb_emit_load(p, tag), tag_type);
lb_emit_store_union_variant_tag(p, variant_ptr, tag_type);
} else {
if (t != t_llvm_bool) {
GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t));
}
}
}
}
File diff suppressed because it is too large Load Diff
+32
View File
@@ -1988,6 +1988,38 @@ bool is_type_simple_compare(Type *t) {
return false;
}
String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
Type *prev_src = src;
// Type *prev_dst = dst;
src = base_type(type_deref(src));
// dst = base_type(type_deref(dst));
bool src_is_ptr = src != prev_src;
// bool dst_is_ptr = dst != prev_dst;
GB_ASSERT(is_type_struct(src) || is_type_union(src));
for_array(i, src->Struct.fields) {
Entity *f = src->Struct.fields[i];
if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) {
if (are_types_identical(dst, f->type)) {
return f->token.string;
}
if (src_is_ptr && is_type_pointer(dst)) {
if (are_types_identical(type_deref(dst), f->type)) {
return f->token.string;
}
}
if (is_type_struct(f->type)) {
String name = lookup_subtype_polymorphic_field(dst, f->type);
if (name.len > 0) {
return name;
}
}
}
}
return str_lit("");
}
Type *strip_type_aliasing(Type *x) {
if (x == nullptr) {