Merge remote-tracking branch 'offical/master'

This commit is contained in:
ed
2025-10-04 10:05:37 -04:00
82 changed files with 4715 additions and 1458 deletions
+13 -15
View File
@@ -418,6 +418,7 @@ enum LinkerChoice : i32 {
Linker_Default = 0,
Linker_lld,
Linker_radlink,
Linker_mold,
Linker_COUNT,
};
@@ -433,6 +434,7 @@ String linker_choices[Linker_COUNT] = {
str_lit("default"),
str_lit("lld"),
str_lit("radlink"),
str_lit("mold"),
};
enum IntegerDivisionByZeroKind : u8 {
@@ -546,6 +548,8 @@ struct BuildContext {
bool ignore_microsoft_magic;
bool linker_map_file;
bool build_diagnostics;
bool use_single_module;
bool use_separate_modules;
bool module_per_file;
@@ -554,6 +558,8 @@ struct BuildContext {
bool internal_no_inline;
bool internal_by_value;
bool internal_weak_monomorphization;
bool internal_ignore_llvm_verification;
bool no_threaded_checker;
@@ -964,14 +970,6 @@ gb_internal bool is_excluded_target_filename(String name) {
return true;
}
if (build_context.command_kind != Command_test) {
String test_suffix = str_lit("_test");
if (string_ends_with(name, test_suffix) && name != test_suffix) {
// Ignore *_test.odin files
return true;
}
}
String str1 = {};
String str2 = {};
isize n = 0;
@@ -1126,7 +1124,7 @@ gb_internal String internal_odin_root_dir(void) {
mutex_lock(&string_buffer_mutex);
defer (mutex_unlock(&string_buffer_mutex));
text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
text = permanent_alloc_array<wchar_t>(len+1);
GetModuleFileNameW(nullptr, text, cast(int)len);
path = string16_to_string(heap_allocator(), make_string16(cast(u16 *)text, len));
@@ -1163,8 +1161,8 @@ gb_internal String internal_odin_root_dir(void) {
return global_module_path;
}
auto path_buf = array_make<char>(heap_allocator(), 300);
defer (array_free(&path_buf));
TEMPORARY_ALLOCATOR_GUARD();
auto path_buf = array_make<char>(temporary_allocator(), 300);
len = 0;
for (;;) {
@@ -1181,7 +1179,7 @@ gb_internal String internal_odin_root_dir(void) {
mutex_lock(&string_buffer_mutex);
defer (mutex_unlock(&string_buffer_mutex));
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
text = permanent_alloc_array<u8>(len + 1);
gb_memmove(text, &path_buf[0], len);
path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr);
@@ -1233,7 +1231,7 @@ gb_internal String internal_odin_root_dir(void) {
mutex_lock(&string_buffer_mutex);
defer (mutex_unlock(&string_buffer_mutex));
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
text = permanent_alloc_array<u8>(len + 1);
gb_memmove(text, &path_buf[0], len);
path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr);
@@ -1394,7 +1392,7 @@ gb_internal String internal_odin_root_dir(void) {
mutex_lock(&string_buffer_mutex);
defer (mutex_unlock(&string_buffer_mutex));
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
text = permanent_alloc_array<u8>(len + 1);
gb_memmove(text, &path_buf[0], len);
@@ -1429,7 +1427,7 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) {
len = GetFullPathNameW(cast(wchar_t *)&string16[0], 0, nullptr, nullptr);
if (len != 0) {
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
wchar_t *text = permanent_alloc_array<wchar_t>(len+1);
GetFullPathNameW(cast(wchar_t *)&string16[0], len, text, nullptr);
mutex_unlock(&fullpath_mutex);
+1 -1
View File
@@ -83,7 +83,7 @@ i32 bundle_android(String original_init_directory) {
return 1;
}
int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
int *dir_numbers = temporary_alloc_array<int>(possible_valid_dirs.count);
char buf[1024] = {};
for_array(i, possible_valid_dirs) {
+13 -13
View File
@@ -354,7 +354,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
}
isize const arg_offset = 1;
auto param_types = slice_make<Type *>(permanent_allocator(), ce->args.count-arg_offset);
auto param_types = permanent_slice_make<Type *>(ce->args.count-arg_offset);
param_types[0] = t_objc_id;
param_types[1] = sel_type;
@@ -462,7 +462,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
{
// NOTE(harold): The last argument specified in the call is the handler proc,
// any other arguments before it are capture by-copy arguments.
auto param_operands = slice_make<Operand>(permanent_allocator(), ce->args.count);
auto param_operands = permanent_slice_make<Operand>(ce->args.count);
isize capture_arg_count = ce->args.count - 1;
@@ -3555,7 +3555,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
case BuiltinProc_compress_values: {
Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count);
Operand *ops = temporary_alloc_array<Operand>(ce->args.count);
isize value_count = 0;
@@ -3686,9 +3686,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
operand->mode = Addressing_Value;
} else {
Type *st = alloc_type_struct_complete();
st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count);
st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count);
st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count);
st->Struct.fields = permanent_slice_make<Entity *>(value_count);
st->Struct.tags = permanent_alloc_array<String>(value_count);
st->Struct.offsets = permanent_alloc_array<i64>(value_count);
Scope *scope = create_scope(c->info, nullptr);
@@ -4388,7 +4388,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
elem = alloc_type_struct();
elem->Struct.scope = s;
elem->Struct.fields = slice_from_array(fields);
elem->Struct.tags = gb_alloc_array(permanent_allocator(), String, fields.count);
elem->Struct.tags = permanent_alloc_array<String>(fields.count);
elem->Struct.node = dummy_node_struct;
type_set_offsets(elem);
wait_signal_set(&elem->Struct.fields_wait_signal);
@@ -4420,7 +4420,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
gb_string_free(s);
return false;
}
auto types = slice_make<Type *>(permanent_allocator(), t->Struct.fields.count-1);
auto types = permanent_slice_make<Type *>(t->Struct.fields.count-1);
for_array(i, types) {
Entity *f = t->Struct.fields[i];
GB_ASSERT(f->type->kind == Type_MultiPointer);
@@ -4756,8 +4756,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (is_type_array(elem)) {
Type *old_array = base_type(elem);
soa_struct = alloc_type_struct();
soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), cast(isize)old_array->Array.count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, cast(isize)old_array->Array.count);
soa_struct->Struct.fields = permanent_slice_make<Entity *>(cast(isize)old_array->Array.count);
soa_struct->Struct.tags = permanent_alloc_array<String>(cast(isize)old_array->Array.count);
soa_struct->Struct.node = operand->expr;
soa_struct->Struct.soa_kind = StructSoa_Fixed;
soa_struct->Struct.soa_elem = elem;
@@ -4789,8 +4789,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
Type *old_struct = base_type(elem);
soa_struct = alloc_type_struct();
soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, old_struct->Struct.fields.count);
soa_struct->Struct.fields = permanent_slice_make<Entity *>(old_struct->Struct.fields.count);
soa_struct->Struct.tags = permanent_alloc_array<String>(old_struct->Struct.fields.count);
soa_struct->Struct.node = operand->expr;
soa_struct->Struct.soa_kind = StructSoa_Fixed;
soa_struct->Struct.soa_elem = elem;
@@ -6182,7 +6182,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
Type *new_type = alloc_type_union();
auto variants = slice_make<Type *>(permanent_allocator(), bt->Union.variants.count);
auto variants = permanent_slice_make<Type *>(bt->Union.variants.count);
for_array(i, bt->Union.variants) {
variants[i] = alloc_type_pointer(bt->Union.variants[i]);
}
+76 -11
View File
@@ -162,8 +162,6 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e
if (found_scope == nullptr) {
return;
}
rw_mutex_lock(&found_scope->mutex);
defer (rw_mutex_unlock(&found_scope->mutex));
// IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the
// original entity was still used check checked, but the checking was only
@@ -172,7 +170,9 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e
// Therefore two things can be done: the type can be assigned to state that it
// has been "evaluated" and the variant data can be copied across
rw_mutex_lock(&found_scope->mutex);
string_map_set(&found_scope->elements, original_name, new_entity);
rw_mutex_unlock(&found_scope->mutex);
original_entity->flags |= EntityFlag_Overridden;
original_entity->type = new_entity->type;
@@ -851,6 +851,50 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) {
}
}
Type *x_base = base_type(x);
Type *y_base = base_type(y);
if (x_base == y_base) {
return true;
}
if (x_base->kind == y_base->kind &&
x_base->kind == Type_Struct) {
i64 xs = type_size_of(x_base);
i64 ys = type_size_of(y_base);
i64 xa = type_align_of(x_base);
i64 ya = type_align_of(y_base);
if (x_base->Struct.is_raw_union == y_base->Struct.is_raw_union &&
xs == ys && xa == ya) {
if (xs > 16) {
// @@ABI NOTE(bill): Just allow anything over 16-bytes to be allowed, because on all current ABIs
// it will be passed by point
// NOTE(bill): this must be changed when ABI changes
return true;
}
if (x_base->Struct.is_raw_union) {
return true;
}
if (x->Struct.fields.count == y->Struct.fields.count) {
for (isize i = 0; i < x->Struct.fields.count; i++) {
Entity *a = x->Struct.fields[i];
Entity *b = y->Struct.fields[i];
bool similar = signature_parameter_similar_enough(a->type, b->type);
if (!similar) {
// NOTE(bill): If the fields are not similar enough, then stop.
goto end;
}
}
}
// HACK NOTE(bill): Allow this for the time begin until it actually becomes a practical problem
return true;
}
}
end:;
return are_types_identical(x, y);
}
@@ -948,7 +992,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e)
error(ident, "foreign library names must be an identifier");
} else {
String name = ident->Ident.token.string;
Entity *found = scope_lookup(ctx->scope, name);
Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash);
if (found == nullptr) {
if (is_blank_ident(name)) {
@@ -1549,7 +1593,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
"\tother at %s",
LIT(name), token_pos_to_string(pos));
} else if (name == "main") {
if (d->entity->pkg->kind != Package_Runtime) {
if (d->entity.load()->pkg->kind != Package_Runtime) {
error(d->proc_lit, "The link name 'main' is reserved for internal use");
}
} else {
@@ -1565,7 +1609,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
@@ -1686,7 +1730,28 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast
check_expr_with_type_hint(ctx, &o, init_expr, e->type);
check_init_variable(ctx, e, &o, str_lit("variable declaration"));
if (e->Variable.is_rodata && o.mode != Addressing_Constant) {
ERROR_BLOCK();
error(o.expr, "Variables declared with @(rodata) must have constant initialization");
Ast *expr = unparen_expr(o.expr);
if (is_type_struct(e->type) && expr && expr->kind == Ast_CompoundLit) {
ast_node(cl, CompoundLit, expr);
for (Ast *elem_ : cl->elems) {
Ast *elem = elem_;
if (elem->kind == Ast_FieldValue) {
elem = elem->FieldValue.value;
}
elem = unparen_expr(elem);
Entity *e = entity_of_node(elem);
if (elem->tav.mode != Addressing_Constant && e == nullptr && elem->kind != Ast_ProcLit) {
Token tok = ast_token(elem);
TokenPos pos = tok.pos;
gbString s = type_to_string(type_of_expr(elem));
error_line("%s Element is not constant, which is required for @(rodata), of type %s\n", token_pos_to_string(pos), s);
gb_string_free(s);
}
}
}
}
check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
@@ -1915,7 +1980,7 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
rw_mutex_shared_lock(&decl->deps_mutex);
rw_mutex_lock(&decl->parent->deps_mutex);
for (Entity *e : decl->deps) {
FOR_PTR_SET(e, decl->deps) {
ptr_set_add(&decl->parent->deps, e);
}
@@ -1967,8 +2032,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
ctx->curr_proc_sig = type;
ctx->curr_proc_calling_convention = type->Proc.calling_convention;
if (decl->parent && decl->entity && decl->parent->entity) {
decl->entity->parent_proc_decl = decl->parent;
if (decl->parent && decl->entity.load() && decl->parent->entity) {
decl->entity.load()->parent_proc_decl = decl->parent;
}
if (ctx->pkg->name != "runtime") {
@@ -1981,9 +2046,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
ast_node(bs, BlockStmt, body);
TEMPORARY_ALLOCATOR_GUARD();
Array<ProcUsingVar> using_entities = {};
using_entities.allocator = heap_allocator();
defer (array_free(&using_entities));
using_entities.allocator = temporary_allocator();
{
if (type->Proc.param_count > 0) {
@@ -2072,7 +2137,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked);
if (decl->defer_use_checked) {
GB_ASSERT(is_type_polymorphic(type, true));
error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string));
error(token, "Defer Use Checked: %.*s", LIT(decl->entity.load()->token.string));
GB_ASSERT(decl->defer_use_checked == false);
}
+231 -160
View File
@@ -587,6 +587,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
d->proc_lit = proc_lit;
d->proc_checked_state = ProcCheckedState_Unchecked;
d->defer_use_checked = false;
d->para_poly_original = old_decl->entity;
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
entity->state.store(EntityState_Resolved);
@@ -608,7 +609,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
entity->flags |= EntityFlag_Disabled;
}
d->entity = entity;
d->entity.store(entity);
AstFile *file = nullptr;
{
@@ -821,9 +822,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
}
}
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
if (c->in_enum_type) {
return 3;
if (c != nullptr) {
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
if (c->in_enum_type) {
return 3;
}
}
}
@@ -1293,6 +1296,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
error_line("\t Got: %s\n", s_got);
gb_string_free(s_got);
gb_string_free(s_expected);
Type *tx = x->Proc.params->Tuple.variables[0]->type;
Type *ty = y->Proc.params->Tuple.variables[0]->type;
gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(tx), LIT(type_strings[tx->kind]), tx->Named.type_name, tx->Named.type_name->TypeName.original_type_for_parapoly);
gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(ty), LIT(type_strings[ty->kind]), ty->Named.type_name, ty->Named.type_name->TypeName.original_type_for_parapoly);
} else {
gbString s_expected = type_to_string(y);
gbString s_got = type_to_string(x);
@@ -1738,7 +1746,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam
o->expr = n;
String name = n->Ident.token.string;
Entity *e = scope_lookup(c->scope, name);
Entity *e = scope_lookup(c->scope, name, n->Ident.hash);
if (e == nullptr) {
if (is_blank_ident(name)) {
error(n, "'_' cannot be used as a value");
@@ -2333,6 +2341,20 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
if (in_value.kind == ExactValue_Integer) {
return true;
}
} else if (is_type_typeid(type)) {
if (in_value.kind == ExactValue_Compound) {
ast_node(cl, CompoundLit, in_value.value_compound);
if (cl->elems.count == 0) {
in_value = exact_value_typeid(nullptr);
} else {
return false;
}
}
if (in_value.kind == ExactValue_Typeid) {
if (out_value) *out_value = in_value;
return true;
}
}
return false;
@@ -3503,6 +3525,7 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
bool is_const_expr = x->mode == Addressing_Constant;
Type *bt = base_type(type);
if (is_const_expr && is_type_constant_type(bt)) {
if (core_type(bt)->kind == Type_Basic) {
@@ -3524,6 +3547,9 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
} else if (is_type_slice(type) && is_type_string(x->type)) {
x->mode = Addressing_Value;
} else if (is_type_union(type)) {
if (is_type_union_constantable(type)) {
return true;
}
x->mode = Addressing_Value;
}
if (x->mode == Addressing_Value) {
@@ -4639,7 +4665,6 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
}
gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
// GB_ASSERT_NOT_NULL(target_type);
if (target_type == nullptr || operand->mode == Addressing_Invalid ||
operand->mode == Addressing_Type ||
is_type_typed(operand->type) ||
@@ -4810,7 +4835,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
TEMPORARY_ALLOCATOR_GUARD();
isize count = t->Union.variants.count;
ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count);
ValidIndexAndScore *valids = temporary_alloc_array<ValidIndexAndScore>(count);
isize valid_count = 0;
isize first_success_index = -1;
for_array(i, t->Union.variants) {
@@ -4851,7 +4876,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
break;
}
operand->type = new_type;
operand->mode = Addressing_Value;
if (operand->mode != Addressing_Constant ||
!elem_type_can_be_constant(operand->type)) {
operand->mode = Addressing_Value;
}
break;
} else if (valid_count > 1) {
ERROR_BLOCK();
@@ -5093,7 +5121,11 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
}
if (cl->elems[0]->kind == Ast_FieldValue) {
if (is_type_struct(node->tav.type)) {
if (is_type_raw_union(node->tav.type)) {
if (success_) *success_ = false;
if (finish_) *finish_ = true;
return empty_exact_value;
} else if (is_type_struct(node->tav.type)) {
bool found = false;
for (Ast *elem : cl->elems) {
if (elem->kind != Ast_FieldValue) {
@@ -5102,7 +5134,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
ast_node(fv, FieldValue, elem);
String name = fv->field->Ident.token.string;
Selection sub_sel = lookup_field(node->tav.type, name, false);
defer (array_free(&sub_sel.index));
if (sub_sel.index.count > 0 &&
sub_sel.index[0] == index) {
value = fv->value->tav.value;
@@ -5363,7 +5394,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
}
} else */if (node->kind == Ast_Ident) {
String name = node->Ident.token.string;
return scope_lookup(c->scope, name);
return scope_lookup(c->scope, name, node->Ident.hash);
} else if (!ident_only) if (node->kind == Ast_SelectorExpr) {
ast_node(se, SelectorExpr, node);
if (se->token.kind == Token_ArrowRight) {
@@ -5385,7 +5416,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
if (op_expr->kind == Ast_Ident) {
String op_name = op_expr->Ident.token.string;
Entity *e = scope_lookup(c->scope, op_name);
Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash);
if (e == nullptr) {
return nullptr;
}
@@ -5482,7 +5513,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
if (op_expr->kind == Ast_Ident) {
String op_name = op_expr->Ident.token.string;
Entity *e = scope_lookup(c->scope, op_name);
Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash);
add_entity_use(c, op_expr, e);
expr_entity = e;
@@ -5808,7 +5839,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
switch (entity->kind) {
case Entity_Constant:
operand->value = entity->Constant.value;
operand->value = entity->Constant.value;
operand->mode = Addressing_Constant;
if (operand->value.kind == ExactValue_Procedure) {
Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
@@ -5905,7 +5936,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
return true;
}
} else {
Entity *e = scope_lookup(s, name);
Entity *e = scope_lookup(s, name, i->hash);
if (e != nullptr) {
if (out_scope) *out_scope = e->scope;
return true;
@@ -6029,7 +6060,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
}
rw_mutex_shared_lock(&decl->deps_mutex);
rw_mutex_lock(&c->decl->deps_mutex);
for (Entity *dep : decl->deps) {
FOR_PTR_SET(dep, decl->deps) {
ptr_set_add(&c->decl->deps, dep);
}
rw_mutex_unlock(&c->decl->deps_mutex);
@@ -6257,7 +6288,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
}
GB_ASSERT(ce->split_args);
auto visited = slice_make<bool>(temporary_allocator(), pt->param_count);
auto visited = temporary_slice_make<bool>(pt->param_count);
auto ordered_operands = array_make<Operand>(temporary_allocator(), pt->param_count);
defer ({
for (Operand const &o : ordered_operands) {
@@ -6473,7 +6504,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
}
if (e && e->kind == Entity_Constant && is_type_proc(e->type)) {
if (o->mode != Addressing_Constant) {
bool ok = false;
if (o->mode == Addressing_Constant) {
ok = true;
} else if (o->value.kind == ExactValue_Procedure) {
ok = true;
}
if (!ok) {
if (show_error) {
error(o->expr, "Expected a constant procedure value for the argument '%.*s'", LIT(e->token.string));
}
@@ -6972,6 +7010,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
array_unordered_remove(&procs, proc_index);
continue;
}
if (!pt->Proc.variadic && max_arg_count != ISIZE_MAX && param_count < max_arg_count) {
array_unordered_remove(&procs, proc_index);
continue;
}
proc_index++;
}
}
@@ -6980,10 +7022,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
isize lhs_count = -1;
i32 variadic_index = -1;
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
defer (array_free(&positional_operands));
defer (array_free(&named_operands));
TEMPORARY_ALLOCATOR_GUARD();
auto positional_operands = array_make<Operand>(temporary_allocator(), 0, 0);
auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0);
if (procs.count == 1) {
Entity *e = procs[0];
@@ -7024,7 +7066,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
if (proc_arg_count >= 0) {
lhs_count = proc_arg_count;
if (lhs_count > 0) {
lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count);
lhs = gb_alloc_array(temporary_allocator(), Entity *, lhs_count);
for (isize param_index = 0; param_index < lhs_count; param_index++) {
Entity *e = nullptr;
for (Entity *p : procs) {
@@ -7110,13 +7152,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
array_add(&named_operands, o);
}
gb_free(heap_allocator(), lhs);
auto valids = array_make<ValidIndexAndScore>(temporary_allocator(), 0, procs.count);
auto valids = array_make<ValidIndexAndScore>(heap_allocator(), 0, procs.count);
defer (array_free(&valids));
auto proc_entities = array_make<Entity *>(heap_allocator(), 0, procs.count*2 + 1);
defer (array_free(&proc_entities));
auto proc_entities = array_make<Entity *>(temporary_allocator(), 0, procs.count*2 + 1);
for (Entity *proc : procs) {
array_add(&proc_entities, proc);
}
@@ -7247,7 +7285,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
}
// Try to reduce the list further for `$T: typeid` like parameters
bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count);
bool *possibly_ignore = temporary_alloc_array<bool>(procs.count);
isize possibly_ignore_set = 0;
if (true) {
@@ -7335,7 +7373,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
}
isize max_spaces = gb_max(max_name_length, max_type_length);
char *spaces = gb_alloc_array(temporary_allocator(), char, max_spaces+1);
char *spaces = temporary_alloc_array<char>(max_spaces+1);
for (isize i = 0; i < max_spaces; i++) {
spaces[i] = ' ';
}
@@ -7510,11 +7548,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
return check_call_arguments_proc_group(c, operand, call);
}
auto positional_operands = array_make<Operand>(heap_allocator(), 0, positional_args.count);
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
TEMPORARY_ALLOCATOR_GUARD();
defer (array_free(&positional_operands));
defer (array_free(&named_operands));
auto positional_operands = array_make<Operand>(temporary_allocator(), 0, positional_args.count);
auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0);
if (positional_args.count > 0) {
Entity **lhs = nullptr;
@@ -7601,6 +7638,8 @@ gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_
gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) {
TEMPORARY_ALLOCATOR_GUARD();
ast_node(ce, CallExpr, call);
Type *original_type = operand->type;
@@ -7609,7 +7648,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
bool show_error = true;
Array<Operand> operands = {};
defer (array_free(&operands));
CallArgumentError err = CallArgumentError_None;
@@ -7617,15 +7655,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
{
// NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves
auto prev_type_path = c->type_path;
c->type_path = new_checker_type_path();
defer ({
destroy_checker_type_path(c->type_path);
c->type_path = prev_type_path;
});
TEMPORARY_ALLOCATOR_GUARD();
c->type_path = new_checker_type_path(temporary_allocator());
defer (c->type_path = prev_type_path);
if (is_call_expr_field_value(ce)) {
named_fields = true;
operands = array_make<Operand>(heap_allocator(), ce->args.count);
operands = array_make<Operand>(temporary_allocator(), ce->args.count);
for_array(i, ce->args) {
Ast *arg = ce->args[i];
ast_node(fv, FieldValue, arg);
@@ -7657,7 +7694,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
}
} else {
operands = array_make<Operand>(heap_allocator(), 0, 2*ce->args.count);
operands = array_make<Operand>(temporary_allocator(), 0, 2*ce->args.count);
Entity **lhs = nullptr;
isize lhs_count = -1;
@@ -7699,7 +7736,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
} else {
TEMPORARY_ALLOCATOR_GUARD();
bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count);
bool *visited = temporary_alloc_array<bool>(param_count);
// LEAK(bill)
ordered_operands = array_make<Operand>(permanent_allocator(), param_count);
@@ -7883,11 +7920,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
{
GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type);
mutex_lock(&found_gen_types->mutex);
defer (mutex_unlock(&found_gen_types->mutex));
Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands);
Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands);
if (found_entity) {
operand->mode = Addressing_Type;
operand->type = found_entity->type;
@@ -8015,6 +8051,106 @@ gb_internal bool check_call_parameter_mixture(Slice<Ast *> const &args, char con
return Expr_Stmt; \
}
gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *operand, Ast *call, Slice<Ast *> const &args, Type *type_hint) {
GB_ASSERT(operand->mode == Addressing_Type);
Type *t = operand->type;
if (is_type_polymorphic_record(t)) {
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
if (!is_type_named(t)) {
gbString s = expr_to_string(operand->expr);
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
gb_string_free(s);
operand->mode = Addressing_Invalid;
operand->type = t_invalid;;
return Expr_Expr;
}
auto err = check_polymorphic_record_type(c, operand, call);
if (err == 0) {
Ast *ident = operand->expr;
while (ident->kind == Ast_SelectorExpr) {
Ast *s = ident->SelectorExpr.selector;
ident = s;
}
Type *ot = operand->type;
GB_ASSERT(ot->kind == Type_Named);
Entity *e = ot->Named.type_name;
add_entity_use(c, ident, e);
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
} else {
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
}
} else {
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
operand->mode = Addressing_Invalid;
isize arg_count = args.count;
switch (arg_count) {
case 0:
{
gbString str = type_to_string(t);
error(call, "Missing argument in conversion to '%s'", str);
gb_string_free(str);
} break;
default:
{
gbString str = type_to_string(t);
if (t->kind == Type_Basic) {
ERROR_BLOCK();
switch (t->Basic.kind) {
case Basic_complex32:
case Basic_complex64:
case Basic_complex128:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
break;
case Basic_quaternion64:
case Basic_quaternion128:
case Basic_quaternion256:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
break;
default:
error(call, "Too many arguments in conversion to '%s'", str);
}
} else {
error(call, "Too many arguments in conversion to '%s'", str);
}
gb_string_free(str);
} break;
case 1: {
Ast *arg = args[0];
if (arg->kind == Ast_FieldValue) {
error(call, "'field = value' cannot be used in a type conversion");
arg = arg->FieldValue.value;
// NOTE(bill): Carry on the cast regardless
}
check_expr_with_type_hint(c, operand, arg, t);
if (operand->mode != Addressing_Invalid) {
if (is_type_polymorphic(t)) {
error(call, "A polymorphic type cannot be used in a type conversion");
} else {
// NOTE(bill): Otherwise the compiler can override the polymorphic type
// as it assumes it is determining the type
check_cast(c, operand, t);
}
}
operand->type = t;
operand->expr = call;
if (operand->mode != Addressing_Invalid) {
update_untyped_expr_type(c, arg, t, false);
}
break;
}
}
}
return Expr_Expr;
}
gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, Type *type_hint) {
if (proc != nullptr &&
@@ -8071,99 +8207,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
}
if (operand->mode == Addressing_Type) {
Type *t = operand->type;
if (is_type_polymorphic_record(t)) {
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
if (!is_type_named(t)) {
gbString s = expr_to_string(operand->expr);
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
gb_string_free(s);
operand->mode = Addressing_Invalid;
operand->type = t_invalid;;
return Expr_Expr;
}
auto err = check_polymorphic_record_type(c, operand, call);
if (err == 0) {
Ast *ident = operand->expr;
while (ident->kind == Ast_SelectorExpr) {
Ast *s = ident->SelectorExpr.selector;
ident = s;
}
Type *ot = operand->type;
GB_ASSERT(ot->kind == Type_Named);
Entity *e = ot->Named.type_name;
add_entity_use(c, ident, e);
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
} else {
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
}
} else {
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
operand->mode = Addressing_Invalid;
isize arg_count = args.count;
switch (arg_count) {
case 0:
{
gbString str = type_to_string(t);
error(call, "Missing argument in conversion to '%s'", str);
gb_string_free(str);
} break;
default:
{
gbString str = type_to_string(t);
if (t->kind == Type_Basic) {
ERROR_BLOCK();
switch (t->Basic.kind) {
case Basic_complex32:
case Basic_complex64:
case Basic_complex128:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
break;
case Basic_quaternion64:
case Basic_quaternion128:
case Basic_quaternion256:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
break;
default:
error(call, "Too many arguments in conversion to '%s'", str);
}
} else {
error(call, "Too many arguments in conversion to '%s'", str);
}
gb_string_free(str);
} break;
case 1: {
Ast *arg = args[0];
if (arg->kind == Ast_FieldValue) {
error(call, "'field = value' cannot be used in a type conversion");
arg = arg->FieldValue.value;
// NOTE(bill): Carry on the cast regardless
}
check_expr_with_type_hint(c, operand, arg, t);
if (operand->mode != Addressing_Invalid) {
if (is_type_polymorphic(t)) {
error(call, "A polymorphic type cannot be used in a type conversion");
} else {
// NOTE(bill): Otherwise the compiler can override the polymorphic type
// as it assumes it is determining the type
check_cast(c, operand, t);
}
}
operand->type = t;
operand->expr = call;
if (operand->mode != Addressing_Invalid) {
update_untyped_expr_type(c, arg, t, false);
}
break;
}
}
}
return Expr_Expr;
return check_call_expr_as_type_cast(c, operand, call, args, type_hint);
}
if (operand->mode == Addressing_Builtin) {
@@ -8335,9 +8379,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
if (c->curr_proc_decl == nullptr) {
error(call, "Calling a '#force_inline' procedure that enables target features is not allowed at file scope");
} else {
GB_ASSERT(c->curr_proc_decl->entity);
GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc);
String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature;
Entity *e = c->curr_proc_decl->entity.load();
GB_ASSERT(e);
GB_ASSERT(e->type->kind == Type_Proc);
String scope_features = e->type->Proc.enable_target_feature;
if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) {
ERROR_BLOCK();
error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid));
@@ -8630,7 +8675,7 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Ope
return true;
}
gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) {
gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o, Type *field_type) {
if (is_operand_nil(*o)) {
return true;
}
@@ -8645,6 +8690,13 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera
return true;
}
}
if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) {
add_type_info_type(c, o->type);
return true;
}
if (is_type_any(field_type)) {
return false;
}
return o->mode == Addressing_Constant;
}
@@ -8874,7 +8926,7 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op
isize count = multi_map_count(seen, key);
if (count) {
TEMPORARY_ALLOCATOR_GUARD();
TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count);
TypeAndToken *taps = temporary_alloc_array<TypeAndToken>(count);
multi_map_get_all(seen, key, taps);
for (isize i = 0; i < count; i++) {
@@ -9595,8 +9647,7 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
break;
}
}
if (is_constant &&
(is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) {
if (is_constant && elem_cannot_be_constant(ft)) {
is_constant = false;
}
}
@@ -9631,11 +9682,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
Operand o = {};
check_expr_or_type(c, &o, fv->value, field->type);
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
if (elem_cannot_be_constant(field->type)) {
is_constant = false;
}
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &o);
is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
}
u8 prev_bit_field_bit_size = c->bit_field_bit_size;
@@ -9668,7 +9719,10 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
}
gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) {
if (cl->elems.count == 0) {
return false;
}
if ((check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) {
ERROR_BLOCK();
error(node, "Compound literals of dynamic types are disabled by default");
error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
@@ -9679,9 +9733,13 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom
error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
}
return false;
} else if (c->curr_proc_decl != nullptr && c->curr_proc_calling_convention != ProcCC_Odin) {
if (c->scope != nullptr && (c->scope->flags & ScopeFlag_ContextDefined) == 0) {
error(node, "Compound literals of dynamic types require a 'context' to defined");
}
}
return cl->elems.count > 0;
return true;
}
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) {
@@ -9801,7 +9859,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (t->Struct.is_raw_union) {
if (cl->elems.count > 0) {
// NOTE: unions cannot be constant
is_constant = false;
is_constant = elem_type_can_be_constant(t);
if (cl->elems[0]->kind != Ast_FieldValue) {
gbString type_str = type_to_string(type);
@@ -9861,11 +9919,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
Operand o = {};
check_expr_or_type(c, &o, elem, field->type);
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
if (elem_cannot_be_constant(field->type)) {
is_constant = false;
}
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &o);
is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
}
check_assignment(c, &o, field->type, str_lit("structure literal"));
@@ -10010,7 +10068,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
} else {
Operand op_index = {};
check_expr(c, &op_index, fv->field);
@@ -10042,7 +10102,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
}
}
@@ -10069,7 +10131,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, e, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
}
if (max < index) {
@@ -10243,7 +10307,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
TokenKind upper_op = Token_LtEq;
if (op.kind == Token_RangeHalf) {
@@ -10284,7 +10350,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
add_to_seen_map(c, &seen, op_index);
}
@@ -10314,7 +10382,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
check_expr_with_type_hint(c, &operand, e, elem_type);
check_assignment(c, &operand, elem_type, context_name);
is_constant = is_constant && operand.mode == Addressing_Constant;
if (is_constant) {
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
}
}
if (max < index) {
@@ -10920,7 +10990,7 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast
}
}
auto modified_args = slice_make<Ast *>(heap_allocator(), ce->args.count+1);
auto modified_args = permanent_slice_make<Ast *>(ce->args.count+1);
modified_args[0] = first_arg;
slice_copy(&modified_args, ce->args, 1);
ce->args = modified_args;
@@ -11423,6 +11493,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
o->mode = Addressing_Value;
o->type = type;
o->value = exact_value_procedure(node);
case_end;
case_ast_node(te, TernaryIfExpr, node);
+84 -63
View File
@@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
}
if (ident_node != nullptr) {
ast_node(i, Ident, ident_node);
e = scope_lookup(ctx->scope, i->token.string);
e = scope_lookup(ctx->scope, i->token.string, i->hash);
if (e != nullptr && e->kind == Entity_Variable) {
used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case
}
@@ -1812,8 +1812,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed");
}
if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
String name = rs->vals[0]->Ident.token.string;
Entity *found = scope_lookup(ctx->scope, name);
AstIdent *ident = &rs->vals[0]->Ident;
String name = ident->token.string;
Entity *found = scope_lookup(ctx->scope, name, ident->hash);
if (found && are_types_identical(found->type, t->BitSet.elem)) {
ERROR_BLOCK();
gbString s = expr_to_string(expr);
@@ -1857,8 +1858,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
error(node, "#reverse for is not supported for map types, as maps are unordered");
}
if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
String name = rs->vals[0]->Ident.token.string;
Entity *found = scope_lookup(ctx->scope, name);
AstIdent *ident = &rs->vals[0]->Ident;
String name = ident->token.string;
Entity *found = scope_lookup(ctx->scope, name, ident->hash);
if (found && are_types_identical(found->type, t->Map.key)) {
ERROR_BLOCK();
gbString s = expr_to_string(expr);
@@ -1963,7 +1965,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
}
auto rhs = slice_from_array(vals);
auto lhs = slice_make<Ast *>(temporary_allocator(), rhs.count);
auto lhs = temporary_slice_make<Ast *>(rhs.count);
slice_copy(&lhs, rs->vals);
isize addressable_index = cast(isize)is_map;
@@ -2539,6 +2541,78 @@ gb_internal void check_if_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
check_close_scope(ctx);
}
// NOTE(bill): This is very basic escape analysis
// This needs to be improved tremendously, and a lot of it done during the
// middle-end (or LLVM side) to improve checks and error messages
void check_unsafe_return(Operand const &o, Type *type, Ast *expr) {
auto const unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) {
gbString s = expr_to_string(o.expr);
if (extra_type) {
gbString t = type_to_string(extra_type);
error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t);
gb_string_free(t);
} else {
error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s);
}
gb_string_free(s);
};
if (type == nullptr || expr == nullptr) {
return;
}
if (expr->kind == Ast_CompoundLit && is_type_slice(type)) {
ast_node(cl, CompoundLit, expr);
if (cl->elems.count == 0) {
return;
}
unsafe_return_error(o, "a compound literal of a slice");
} else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
Ast *x = unparen_expr(expr->UnaryExpr.expr);
Entity *e = entity_of_node(x);
if (is_entity_local_variable(e)) {
unsafe_return_error(o, "the address of a local variable");
} else if (x->kind == Ast_CompoundLit) {
unsafe_return_error(o, "the address of a compound literal");
} else if (x->kind == Ast_IndexExpr) {
Entity *f = entity_of_node(x->IndexExpr.expr);
if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
if (is_entity_local_variable(f)) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (x->kind == Ast_MatrixIndexExpr) {
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (expr->kind == Ast_SliceExpr) {
Ast *x = unparen_expr(expr->SliceExpr.expr);
Entity *e = entity_of_node(x);
if (is_entity_local_variable(e) && is_type_array(e->type)) {
unsafe_return_error(o, "a slice of a local variable");
} else if (x->kind == Ast_CompoundLit) {
unsafe_return_error(o, "a slice of a compound literal");
}
} else if (o.mode == Addressing_Constant && is_type_slice(type)) {
ERROR_BLOCK();
unsafe_return_error(o, "a compound literal of a slice");
error_line("\tNote: A constant slice value will use the memory of the current stack frame\n");
} else if (expr->kind == Ast_CompoundLit) {
ast_node(cl, CompoundLit, expr);
for (Ast *elem : cl->elems) {
if (elem->kind == Ast_FieldValue) {
ast_node(fv, FieldValue, elem);
Entity *e = entity_of_node(fv->field);
if (e != nullptr) {
check_unsafe_return(o, e->type, fv->value);
}
}
}
}
}
gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
ast_node(rs, ReturnStmt, node);
@@ -2567,8 +2641,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
result_count = proc_type->Proc.results->Tuple.variables.count;
}
auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
defer (array_free(&operands));
TEMPORARY_ALLOCATOR_GUARD();
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*rs->results.count);
check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
@@ -2614,61 +2689,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
expr = unparen_expr(arg);
}
auto unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) {
gbString s = expr_to_string(o.expr);
if (extra_type) {
gbString t = type_to_string(extra_type);
error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t);
gb_string_free(t);
} else {
error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s);
}
gb_string_free(s);
};
// NOTE(bill): This is very basic escape analysis
// This needs to be improved tremendously, and a lot of it done during the
// middle-end (or LLVM side) to improve checks and error messages
if (expr->kind == Ast_CompoundLit && is_type_slice(o.type)) {
ast_node(cl, CompoundLit, expr);
if (cl->elems.count == 0) {
continue;
}
unsafe_return_error(o, "a compound literal of a slice");
} else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
Ast *x = unparen_expr(expr->UnaryExpr.expr);
Entity *e = entity_of_node(x);
if (is_entity_local_variable(e)) {
unsafe_return_error(o, "the address of a local variable");
} else if (x->kind == Ast_CompoundLit) {
unsafe_return_error(o, "the address of a compound literal");
} else if (x->kind == Ast_IndexExpr) {
Entity *f = entity_of_node(x->IndexExpr.expr);
if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
if (is_entity_local_variable(f)) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (x->kind == Ast_MatrixIndexExpr) {
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (expr->kind == Ast_SliceExpr) {
Ast *x = unparen_expr(expr->SliceExpr.expr);
Entity *e = entity_of_node(x);
if (is_entity_local_variable(e) && is_type_array(e->type)) {
unsafe_return_error(o, "a slice of a local variable");
} else if (x->kind == Ast_CompoundLit) {
unsafe_return_error(o, "a slice of a compound literal");
}
} else if (o.mode == Addressing_Constant && is_type_slice(o.type)) {
ERROR_BLOCK();
unsafe_return_error(o, "a compound literal of a slice");
error_line("\tNote: A constant slice value will use the memory of the current stack frame\n");
}
check_unsafe_return(o, o.type, expr);
}
}
+27 -25
View File
@@ -267,19 +267,19 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_,
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) {
mutex_lock(&ctx->info->gen_types_mutex); // @@global
GenTypesData *found_gen_types = nullptr;
auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
if (found_gen_types_ptr == nullptr) {
GB_ASSERT(original_type->kind == Type_Named);
mutex_lock(&original_type->Named.gen_types_data_mutex);
if (original_type->Named.gen_types_data == nullptr) {
GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData);
gen_types->types = array_make<Entity *>(heap_allocator());
map_set(&ctx->info->gen_types, original_type, gen_types);
found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
original_type->Named.gen_types_data = gen_types;
}
found_gen_types = *found_gen_types_ptr;
GB_ASSERT(found_gen_types != nullptr);
mutex_unlock(&ctx->info->gen_types_mutex); // @@global
found_gen_types = original_type->Named.gen_types_data;
mutex_unlock(&original_type->Named.gen_types_data_mutex);
return found_gen_types;
}
@@ -312,6 +312,7 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T
e->state = EntityState_Resolved;
e->file = ctx->file;
e->pkg = pkg;
e->TypeName.original_type_for_parapoly = original_type;
add_entity_use(ctx, node, e);
}
@@ -1106,7 +1107,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
GB_ASSERT(fields.count <= bf->fields.count);
auto bit_offsets = slice_make<i64>(permanent_allocator(), fields.count);
auto bit_offsets = permanent_slice_make<i64>(fields.count);
i64 curr_offset = 0;
for_array(i, bit_sizes) {
bit_offsets[i] = curr_offset;
@@ -2707,7 +2708,7 @@ gb_internal Type *get_map_cell_type(Type *type) {
// Padding exists
Type *s = alloc_type_struct();
Scope *scope = create_scope(nullptr, nullptr);
s->Struct.fields = slice_make<Entity *>(permanent_allocator(), 2);
s->Struct.fields = permanent_slice_make<Entity *>(2);
s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved);
s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved);
s->Struct.scope = scope;
@@ -2732,7 +2733,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
Type *metadata_type = alloc_type_struct();
Scope *metadata_scope = create_scope(nullptr, nullptr);
metadata_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 5);
metadata_type->Struct.fields = permanent_slice_make<Entity *>(5);
metadata_type->Struct.fields[0] = alloc_entity_field(metadata_scope, make_token_ident("key"), key, false, 0, EntityState_Resolved);
metadata_type->Struct.fields[1] = alloc_entity_field(metadata_scope, make_token_ident("value"), value, false, 1, EntityState_Resolved);
metadata_type->Struct.fields[2] = alloc_entity_field(metadata_scope, make_token_ident("hash"), t_uintptr, false, 2, EntityState_Resolved);
@@ -2750,7 +2751,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
Scope *scope = create_scope(nullptr, nullptr);
Type *debug_type = alloc_type_struct();
debug_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 3);
debug_type->Struct.fields = permanent_slice_make<Entity *>(3);
debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved);
debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved);
debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved);
@@ -2983,13 +2984,13 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis
if (wait_to_finish) {
wait_signal_until_available(&old_struct->Struct.fields_wait_signal);
} else {
GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load());
GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load() != 0);
}
field_count = old_struct->Struct.fields.count;
t->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
t->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
t->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
auto const &add_entity = [](Scope *scope, Entity *entity) {
@@ -3107,7 +3108,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
if (is_polymorphic) {
field_count = 0;
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
soa_struct->Struct.soa_count = 0;
@@ -3117,7 +3118,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
Type *old_array = base_type(elem);
field_count = cast(isize)old_array->Array.count;
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
string_map_init(&scope->elements, 8);
@@ -3159,8 +3160,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
if (old_struct->Struct.fields_wait_signal.futex.load()) {
field_count = old_struct->Struct.fields.count;
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
soa_struct->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
for_array(i, old_struct->Struct.fields) {
Entity *old_field = old_struct->Struct.fields[i];
@@ -3355,7 +3356,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
}
}
gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
GB_ASSERT_NOT_NULL(type);
GB_ASSERT(type != nullptr);
if (e == nullptr) {
*type = t_invalid;
return true;
@@ -3512,8 +3513,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
case_ast_node(pt, PointerType, e);
CheckerContext c = *ctx;
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
TEMPORARY_ALLOCATOR_GUARD();
c.type_path = new_checker_type_path(temporary_allocator());
Type *elem = t_invalid;
Operand o = {};
@@ -3747,8 +3749,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
CheckerContext c = *ctx;
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
TEMPORARY_ALLOCATOR_GUARD();
c.type_path = new_checker_type_path(temporary_allocator());
return check_type_expr(&c, e, nullptr);
}
+435 -229
View File
File diff suppressed because it is too large Load Diff
+17 -14
View File
@@ -209,7 +209,7 @@ struct DeclInfo {
Scope * scope;
Entity *entity;
std::atomic<Entity *> entity;
Ast * decl_node;
Ast * type_expr;
@@ -218,6 +218,8 @@ struct DeclInfo {
Ast * proc_lit; // Ast_ProcLit
Type * gen_proc_type; // Precalculated
Entity * para_poly_original;
bool is_using;
bool where_clauses_evaluated;
bool foreign_require_results;
@@ -309,11 +311,12 @@ struct EntityGraphNode;
typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
struct EntityGraphNode {
Entity * entity; // Procedure, Variable, Constant
Entity *entity; // Procedure, Variable, Constant
EntityGraphNodeSet pred;
EntityGraphNodeSet succ;
isize index; // Index in array/queue
isize dep_count;
isize index; // Index in array/queue
isize dep_count;
};
@@ -448,9 +451,11 @@ struct CheckerInfo {
AstPackage * init_package;
Scope * init_scope;
Entity * entry_point;
PtrSet<Entity *> minimum_dependency_set;
BlockingMutex minimum_dependency_type_info_mutex;
RwMutex minimum_dependency_type_info_mutex;
PtrMap</*type info hash*/u64, /*min dep index*/isize> min_dep_type_info_index_map;
RWSpinLock min_dep_type_info_set_mutex;
TypeSet min_dep_type_info_set;
Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count
@@ -477,8 +482,6 @@ struct CheckerInfo {
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
BlockingMutex gen_types_mutex;
PtrMap<Type *, GenTypesData *> gen_types;
// BlockingMutex type_info_mutex; // NOT recursive
// Array<TypeInfoPair> type_info_types;
@@ -514,7 +517,7 @@ struct CheckerInfo {
BlockingMutex load_file_mutex;
StringMap<LoadFileCache *> load_file_cache;
BlockingMutex all_procedures_mutex;
MPSCQueue<ProcInfo *> all_procedures_queue;
Array<ProcInfo *> all_procedures;
BlockingMutex instrumentation_mutex;
@@ -622,12 +625,12 @@ gb_internal Entity *entity_of_node(Ast *expr);
gb_internal Entity *scope_lookup_current(Scope *s, String const &name);
gb_internal Entity *scope_lookup (Scope *s, String const &name);
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
gb_internal Entity *scope_lookup (Scope *s, String const &name, u32 hash=0);
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, u32 hash=0);
gb_internal Entity *scope_insert (Scope *s, Entity *entity);
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value);
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true);
gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value);
gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
@@ -648,8 +651,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
gb_internal CheckerTypePath *new_checker_type_path();
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator);
gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator);
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
gb_internal Entity *check_type_path_pop (CheckerContext *c);
+54 -4
View File
@@ -113,6 +113,13 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
return ptr;
}
template <typename T>
gb_internal T *arena_alloc_item(Arena *arena) {
return cast(T *)arena_alloc(arena, gb_size_of(T), gb_align_of(T));
}
gb_internal void arena_free_all(Arena *arena) {
while (arena->curr_block != nullptr) {
MemoryBlock *free_block = arena->curr_block;
@@ -346,7 +353,7 @@ gb_internal gbAllocator arena_allocator(Arena *arena) {
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) {
void *ptr = nullptr;
Arena *arena = cast(Arena *)allocator_data;
GB_ASSERT_NOT_NULL(arena);
GB_ASSERT(arena != nullptr);
switch (type) {
case gbAllocation_Alloc:
@@ -394,6 +401,48 @@ gb_internal Arena *get_arena(ThreadArenaKind kind) {
}
template <typename T>
gb_internal T *permanent_alloc_item() {
Arena *arena = get_arena(ThreadArena_Permanent);
return arena_alloc_item<T>(arena);
}
template <typename T>
gb_internal T *permanent_alloc_array(isize count) {
Arena *arena = get_arena(ThreadArena_Permanent);
return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
}
template <typename T>
gb_internal Slice<T> permanent_slice_make(isize count) {
Arena *arena = get_arena(ThreadArena_Permanent);
T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
return {data, count};
}
template <typename T>
gb_internal T *temporary_alloc_item() {
Arena *arena = get_arena(ThreadArena_Temporary);
return arena_alloc_item<T>(arena);
}
template <typename T>
gb_internal T *temporary_alloc_array(isize count) {
Arena *arena = get_arena(ThreadArena_Temporary);
return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
}
template <typename T>
gb_internal Slice<T> temporary_slice_make(isize count) {
Arena *arena = get_arena(ThreadArena_Temporary);
T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
return {data, count};
}
gb_internal GB_ALLOCATOR_PROC(thread_arena_allocator_proc) {
void *ptr = nullptr;
@@ -432,15 +481,16 @@ gb_internal gbAllocator permanent_allocator() {
}
gb_internal gbAllocator temporary_allocator() {
return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Permanent};
// return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Temporary};
return permanent_allocator();
}
#define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena}
// #define TEMPORARY_ALLOCATOR_GUARD()
#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary))
// #define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary))
#define TEMPORARY_ALLOCATOR_GUARD()
#define PERMANENT_ALLOCATOR_GUARD()
+3 -1
View File
@@ -164,6 +164,7 @@ struct Entity {
u64 id;
std::atomic<u64> flags;
std::atomic<EntityState> state;
std::atomic<i32> min_dep_count;
Token token;
Scope * scope;
Type * type;
@@ -233,6 +234,7 @@ struct Entity {
} Variable;
struct {
Type * type_parameter_specialization;
Type * original_type_for_parapoly;
String ir_mangled_name;
bool is_type_alias;
bool objc_is_implementation;
@@ -347,7 +349,7 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ
entity->type = type;
entity->id = 1 + global_entity_id.fetch_add(1);
if (token.pos.file_id) {
entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id);
entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id);
}
return entity;
}
+19 -8
View File
@@ -86,7 +86,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos);
gb_internal bool set_file_path_string(i32 index, String const &path) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
// mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_file_path_strings.count) {
@@ -99,14 +99,14 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
// mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
// mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_files.count) {
@@ -118,13 +118,13 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
ok = true;
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
// mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
gb_internal String get_file_path_string(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
// mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
String path = {};
@@ -133,13 +133,13 @@ gb_internal String get_file_path_string(i32 index) {
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
// mutex_unlock(&global_error_collector.path_mutex);
return path;
}
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
// mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
AstFile *file = nullptr;
@@ -148,7 +148,18 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
// mutex_unlock(&global_error_collector.path_mutex);
return file;
}
// use AFTER PARSER
gb_internal AstFile *thread_unsafe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0);
AstFile *file = nullptr;
if (index < global_files.count) {
file = global_files[index];
}
return file;
}
+13 -11
View File
@@ -714,13 +714,15 @@ extern "C++" {
} while (0)
#endif
#if defined(DISABLE_ASSERT)
#define GB_ASSERT(cond) gb_unused(cond)
#endif
#ifndef GB_ASSERT
#define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL)
#endif
#ifndef GB_ASSERT_NOT_NULL
#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL")
#endif
// NOTE(bill): Things that shouldn't happen with a message!
#ifndef GB_PANIC
@@ -3719,7 +3721,7 @@ gb_inline i32 gb_strcmp(char const *s1, char const *s2) {
}
gb_inline char *gb_strcpy(char *dest, char const *source) {
GB_ASSERT_NOT_NULL(dest);
GB_ASSERT(dest != NULL);
if (source) {
char *str = dest;
while (*source) *str++ = *source++;
@@ -3729,7 +3731,7 @@ gb_inline char *gb_strcpy(char *dest, char const *source) {
gb_inline char *gb_strncpy(char *dest, char const *source, isize len) {
GB_ASSERT_NOT_NULL(dest);
GB_ASSERT(dest != NULL);
if (source) {
char *str = dest;
while (len > 0 && *source) {
@@ -3746,7 +3748,7 @@ gb_inline char *gb_strncpy(char *dest, char const *source, isize len) {
gb_inline isize gb_strlcpy(char *dest, char const *source, isize len) {
isize result = 0;
GB_ASSERT_NOT_NULL(dest);
GB_ASSERT(dest != NULL);
if (source) {
char const *source_start = source;
char *str = dest;
@@ -5636,7 +5638,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con
void gb_file_free_contents(gbFileContents *fc) {
if (fc == NULL || fc->size == 0) return;
GB_ASSERT_NOT_NULL(fc->data);
GB_ASSERT(fc->data != NULL);
gb_free(fc->allocator, fc->data);
fc->data = NULL;
fc->size = 0;
@@ -5648,7 +5650,7 @@ void gb_file_free_contents(gbFileContents *fc) {
gb_inline b32 gb_path_is_absolute(char const *path) {
b32 result = false;
GB_ASSERT_NOT_NULL(path);
GB_ASSERT(path != NULL);
#if defined(GB_SYSTEM_WINDOWS)
result == (gb_strlen(path) > 2) &&
gb_char_is_alpha(path[0]) &&
@@ -5663,7 +5665,7 @@ gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolut
gb_inline b32 gb_path_is_root(char const *path) {
b32 result = false;
GB_ASSERT_NOT_NULL(path);
GB_ASSERT(path != NULL);
#if defined(GB_SYSTEM_WINDOWS)
result = gb_path_is_absolute(path) && (gb_strlen(path) == 3);
#else
@@ -5674,14 +5676,14 @@ gb_inline b32 gb_path_is_root(char const *path) {
gb_inline char const *gb_path_base_name(char const *path) {
char const *ls;
GB_ASSERT_NOT_NULL(path);
GB_ASSERT(path != NULL);
ls = gb_char_last_occurence(path, '/');
return (ls == NULL) ? path : ls+1;
}
gb_inline char const *gb_path_extension(char const *path) {
char const *ld;
GB_ASSERT_NOT_NULL(path);
GB_ASSERT(path != NULL);
ld = gb_char_last_occurence(path, '.');
return (ld == NULL) ? NULL : ld+1;
}
+27 -8
View File
@@ -161,21 +161,32 @@ gb_internal i32 linker_stage(LinkerData *gen) {
try_cross_linking:;
#if defined(GB_SYSTEM_WINDOWS)
String section_name = str_lit("msvc-link");
bool is_windows = build_context.metrics.os == TargetOs_windows;
#else
String section_name = str_lit("lld-link");
bool is_windows = false;
#endif
bool is_osx = build_context.metrics.os == TargetOs_darwin;
switch (build_context.linker_choice) {
case Linker_Default: break;
case Linker_lld: section_name = str_lit("lld-link"); break;
#if defined(GB_SYSTEM_LINUX)
case Linker_mold: section_name = str_lit("mold-link"); break;
#endif
#if defined(GB_SYSTEM_WINDOWS)
case Linker_radlink: section_name = str_lit("rad-link"); break;
#endif
default:
gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice]));
return 1;
}
if (is_windows) {
String section_name = str_lit("msvc-link");
switch (build_context.linker_choice) {
case Linker_Default: break;
case Linker_lld: section_name = str_lit("lld-link"); break;
case Linker_radlink: section_name = str_lit("rad-link"); break;
}
timings_start_section(timings, section_name);
gbString lib_str = gb_string_make(heap_allocator(), "");
@@ -281,7 +292,11 @@ try_cross_linking:;
link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
}
} else {
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
// For i386 with CRT, libcmt provides the entry point
// For other cases or no_crt, we need to specify the entry point
if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) {
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
}
}
if (build_context.build_paths[BuildPath_Symbols].name != "") {
@@ -419,7 +434,8 @@ try_cross_linking:;
}
}
} else {
timings_start_section(timings, str_lit("ld-link"));
timings_start_section(timings, section_name);
int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
@@ -952,6 +968,9 @@ try_cross_linking:;
if (build_context.linker_choice == Linker_lld) {
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
result = system_exec_command_line_app("lld-link", link_command_line);
} else if (build_context.linker_choice == Linker_mold) {
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=mold");
result = system_exec_command_line_app("mold-link", link_command_line);
} else {
result = system_exec_command_line_app("ld-link", link_command_line);
}
+17 -17
View File
@@ -522,6 +522,23 @@ namespace lbAbiAmd64Win64 {
}
};
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
return false;
}
if (LLVMCountStructElementTypes(type) != 2) {
return false;
}
LLVMTypeRef fields[2] = {};
LLVMGetStructElementTypes(type, fields);
if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) {
return false;
}
return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8;
}
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
namespace lbAbiAmd64SysV {
enum RegClass {
@@ -652,23 +669,6 @@ namespace lbAbiAmd64SysV {
return false;
}
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
return false;
}
if (LLVMCountStructElementTypes(type) != 2) {
return false;
}
LLVMTypeRef fields[2] = {};
LLVMGetStructElementTypes(type, fields);
if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) {
return false;
}
return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8;
}
gb_internal bool is_aggregate(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
+311 -223
View File
@@ -8,7 +8,11 @@
#endif
#ifndef LLVM_IGNORE_VERIFICATION
#define LLVM_IGNORE_VERIFICATION 0
#define LLVM_IGNORE_VERIFICATION build_context.internal_ignore_llvm_verification
#endif
#ifndef LLVM_WEAK_MONOMORPHIZATION
#define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization)
#endif
@@ -242,26 +246,12 @@ gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type
return proc_name;
}
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(is_type_comparable(type));
gb_internal void lb_equal_proc_generate_body(lbModule *m, lbProcedure *p) {
Type *type = p->internal_gen_type;
Type *pt = alloc_type_pointer(type);
LLVMTypeRef ptr_type = lb_type(m, pt);
String proc_name = lb_internal_gen_name_from_type("__$equal", type);
lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
lbProcedure *compare_proc = nullptr;
if (found) {
compare_proc = *found;
GB_ASSERT(compare_proc != nullptr);
return {compare_proc->value, compare_proc->type};
}
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
LLVMSetLinkage(p->value, LLVMInternalLinkage);
@@ -389,9 +379,29 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
}
lb_end_procedure_body(p);
}
compare_proc = p;
return {compare_proc->value, compare_proc->type};
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(is_type_comparable(type));
String proc_name = lb_internal_gen_name_from_type("__$equal", type);
lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
lbProcedure *p = *found;
GB_ASSERT(p != nullptr);
return {p->value, p->type};
}
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
string_map_set(&m->gen_procs, proc_name, p);
p->internal_gen_type = type;
p->generate_body = lb_equal_proc_generate_body;
// p->generate_body(m, p);
mpsc_enqueue(&m->procedures_to_generate, p);
return {p->value, p->type};
}
gb_internal lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) {
@@ -620,6 +630,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
#define LLVM_SET_VALUE_NAME(value, name) LLVMSetValueName2((value), (name), gb_count_of((name))-1);
gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
GB_ASSERT(!build_context.dynamic_map_calls);
type = base_type(type);
@@ -634,6 +645,9 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc);
string_map_set(&m->gen_procs, proc_name, p);
p->internal_gen_type = type;
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -1153,15 +1167,6 @@ gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_pt
return lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
}
struct lbGlobalVariable {
lbValue var;
lbValue init;
DeclInfo *decl;
bool is_initialized;
};
gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
if (build_context.metrics.os != TargetOs_darwin) {
return nullptr;
@@ -1900,12 +1905,16 @@ gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=fa
}
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
if (LLVM_IGNORE_VERIFICATION) {
return 0;
}
char *llvm_error = nullptr;
defer (LLVMDisposeMessage(llvm_error));
lbModule *m = cast(lbModule *)data;
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error);
if (build_context.keep_temp_files) {
TIME_SECTION("LLVM Print Module to File");
String filepath_ll = lb_filepath_ll_for_module(m);
@@ -1921,6 +1930,132 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
return 0;
}
gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast *init_expr, lbGlobalVariable &var) {
if (init_expr != nullptr) {
lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) {
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
if (is_type_untyped_nil(init.type)) {
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
var.is_initialized = true;
if (e->Variable.is_rodata) {
LLVMSetGlobalConstant(var.var.value, true);
}
return true;
}
GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
}
if (is_type_any(e->type)) {
var.init = init;
} else if (lb_is_const_or_global(init)) {
if (!var.is_initialized) {
if (is_type_proc(init.type)) {
init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
}
LLVMSetInitializer(var.var.value, init.value);
var.is_initialized = true;
if (e->Variable.is_rodata) {
LLVMSetGlobalConstant(var.var.value, true);
}
return true;
}
} else {
var.init = init;
}
}
if (var.init.value != nullptr) {
GB_ASSERT(!var.is_initialized);
Type *t = type_deref(var.var.type);
if (is_type_any(t)) {
// NOTE(bill): Edge case for 'any' type
Type *var_type = default_type(var.init.type);
gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
lbAddr g = lb_add_global_generated_with_name(m, var_type, {}, make_string_c(var_name));
lb_addr_store(p, g, var.init);
lbValue gp = lb_addr_get_ptr(p, g);
lbValue data = lb_emit_struct_ep(p, var.var, 0);
lbValue ti = lb_emit_struct_ep(p, var.var, 1);
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
lb_emit_store(p, ti, lb_typeid(p->module, var_type));
} else {
LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
lbValue src0 = lb_emit_conv(p, var.init, t);
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
LLVMValueRef dst = var.var.value;
LLVMBuildStore(p->builder, src, dst);
}
var.is_initialized = true;
}
return false;
}
gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedure *p) {
lb_begin_procedure_body(p);
lb_setup_type_info_data(m);
if (p->objc_names) {
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(m, p->objc_names->type), p->objc_names->value, nullptr, 0, "");
}
Type *dummy_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
LLVMTypeRef raw_dummy_type = lb_type_internal_for_procedures_raw(m, dummy_type);
for (auto &var : *p->global_variables) {
if (var.is_initialized) {
continue;
}
lbModule *entity_module = m;
Entity *e = var.decl->entity;
GB_ASSERT(e->kind == Entity_Variable);
e->code_gen_module = entity_module;
Ast *init_expr = var.decl->init_expr;
if (init_expr == nullptr && var.init.value == nullptr) {
continue;
}
if (type_size_of(e->type) > 8) {
String ename = lb_get_entity_name(m, e);
gbString name = gb_string_make(permanent_allocator(), "");
name = gb_string_appendc(name, "__$startup$");
name = gb_string_append_length(name, ename.text, ename.len);
lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type);
LLVMSetVisibility(dummy->value, LLVMHiddenVisibility);
LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage);
lb_begin_procedure_body(dummy);
lb_init_global_var(m, dummy, e, init_expr, var);
lb_end_procedure_body(dummy);
LLVMValueRef context_ptr = lb_find_or_generate_context_ptr(p).addr.value;
LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &context_ptr, 1, "");
} else {
lb_init_global_var(m, p, e, init_expr, var);
}
}
CheckerInfo *info = m->gen->info;
for (Entity *e : info->init_procedures) {
lbValue value = lb_find_procedure_value_from_entity(m, e);
lb_emit_call(p, value, {}, ProcInlining_none);
}
lb_end_procedure_body(p);
}
gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
@@ -1935,104 +2070,11 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
LLVMSetVisibility(p->value, LLVMHiddenVisibility);
LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
lb_begin_procedure_body(p);
p->global_variables = &global_variables;
p->objc_names = objc_names;
lb_setup_type_info_data(main_module);
lb_create_startup_runtime_generate_body(main_module, p);
if (objc_names) {
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
}
for (auto &var : global_variables) {
if (var.is_initialized) {
continue;
}
lbModule *entity_module = main_module;
Entity *e = var.decl->entity;
GB_ASSERT(e->kind == Entity_Variable);
e->code_gen_module = entity_module;
Ast *init_expr = var.decl->init_expr;
if (init_expr != nullptr) {
lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) {
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
if (is_type_untyped_nil(init.type)) {
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
var.is_initialized = true;
if (e->Variable.is_rodata) {
LLVMSetGlobalConstant(var.var.value, true);
}
continue;
}
GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
}
if (is_type_any(e->type) || is_type_union(e->type)) {
var.init = init;
} else if (lb_is_const_or_global(init)) {
if (!var.is_initialized) {
if (is_type_proc(init.type)) {
init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
}
LLVMSetInitializer(var.var.value, init.value);
var.is_initialized = true;
if (e->Variable.is_rodata) {
LLVMSetGlobalConstant(var.var.value, true);
}
continue;
}
} else {
var.init = init;
}
}
if (var.init.value != nullptr) {
GB_ASSERT(!var.is_initialized);
Type *t = type_deref(var.var.type);
if (is_type_any(t)) {
// NOTE(bill): Edge case for 'any' type
Type *var_type = default_type(var.init.type);
gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
lbAddr g = lb_add_global_generated_with_name(main_module, var_type, {}, make_string_c(var_name));
lb_addr_store(p, g, var.init);
lbValue gp = lb_addr_get_ptr(p, g);
lbValue data = lb_emit_struct_ep(p, var.var, 0);
lbValue ti = lb_emit_struct_ep(p, var.var, 1);
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
lb_emit_store(p, ti, lb_typeid(p->module, var_type));
} else {
LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
lbValue src0 = lb_emit_conv(p, var.init, t);
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
LLVMValueRef dst = var.var.value;
LLVMBuildStore(p->builder, src, dst);
}
var.is_initialized = true;
}
}
CheckerInfo *info = main_module->gen->info;
for (Entity *e : info->init_procedures) {
lbValue value = lb_find_procedure_value_from_entity(main_module, e);
lb_emit_call(p, value, {}, ProcInlining_none);
}
lb_end_procedure_body(p);
lb_verify_function(main_module, p);
return p;
}
@@ -2073,7 +2115,7 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
for (Entity *e : m->global_procedures_to_create) {
(void)lb_get_entity_name(m, e);
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
mpsc_enqueue(&m->procedures_to_generate, lb_create_procedure(m, e));
}
return 0;
}
@@ -2097,8 +2139,6 @@ gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) {
}
gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) {
auto *min_dep_set = &info->minimum_dependency_set;
for (Entity *e : info->entities) {
String name = e->token.string;
Scope * scope = e->scope;
@@ -2135,14 +2175,19 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
}
}
if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
continue;
}
// if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
// // NOTE(bill): Nothing depends upon it so doesn't need to be built
// continue;
// }
lbModule *m = &gen->default_module;
if (USE_SEPARATE_MODULES) {
m = lb_module_of_entity(gen, e);
m = lb_module_of_entity(gen, e, m);
}
GB_ASSERT(m != nullptr);
@@ -2258,7 +2303,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names);
}
for (lbProcedure *p : m->procedures_to_generate) {
MUTEX_GUARD_BLOCK(&m->generated_procedures_mutex) for (lbProcedure *p : m->generated_procedures) {
if (p->body != nullptr) { // Build Procedure
lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default;
if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
@@ -2297,17 +2342,23 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
}
void lb_remove_unused_functions_and_globals(lbGenerator *gen) {
for (auto &entry : gen->modules) {
lbModule *m = entry.value;
lb_run_remove_unused_function_pass(m);
lb_run_remove_unused_globals_pass(m);
}
}
struct lbLLVMModulePassWorkerData {
lbModule *m;
LLVMTargetMachineRef target_machine;
bool do_threading;
};
gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
auto wd = cast(lbLLVMModulePassWorkerData *)data;
lb_run_remove_unused_function_pass(wd->m);
lb_run_remove_unused_globals_pass(wd->m);
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
LLVMRunPassManager(module_pass_manager, wd->m->mod);
@@ -2383,6 +2434,17 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
return 1;
}
#endif
if (LLVM_IGNORE_VERIFICATION) {
return 0;
}
if (wd->do_threading) {
thread_pool_add_task(lb_llvm_module_verification_worker_proc, wd->m);
} else {
lb_llvm_module_verification_worker_proc(wd->m);
}
return 0;
}
@@ -2390,8 +2452,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
lbModule *m = cast(lbModule *)data;
for (isize i = 0; i < m->procedures_to_generate.count; i++) {
lbProcedure *p = m->procedures_to_generate[i];
for (lbProcedure *p = nullptr; mpsc_dequeue(&m->procedures_to_generate, &p); /**/) {
lb_generate_procedure(p->module, p);
}
return 0;
@@ -2415,10 +2476,15 @@ gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
lbModule *m = cast(lbModule *)data;
for (isize i = 0; i < m->missing_procedures_to_check.count; i++) {
lbProcedure *p = m->missing_procedures_to_check[i];
debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
lb_generate_procedure(m, p);
for (lbProcedure *p = nullptr; mpsc_dequeue(&m->missing_procedures_to_check, &p); /**/) {
if (!p->is_done.load(std::memory_order_relaxed)) {
debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
lb_generate_procedure(m, p);
}
for (lbProcedure *nested = nullptr; mpsc_dequeue(&m->procedures_to_generate, &nested); /**/) {
mpsc_enqueue(&m->missing_procedures_to_check, nested);
}
}
return 0;
}
@@ -2438,6 +2504,12 @@ gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_thread
lb_generate_missing_procedures_to_check_worker_proc(m);
}
}
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
GB_ASSERT(m->missing_procedures_to_check.count == 0);
GB_ASSERT(m->procedures_to_generate.count == 0);
}
}
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
@@ -2465,19 +2537,16 @@ gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
}
gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool do_threading) {
if (do_threading) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
wd->target_machine = m->target_machine;
wd->do_threading = true;
if (do_threading) {
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
} else {
lb_llvm_module_pass_worker_proc(wd);
}
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
}
thread_pool_wait();
} else {
@@ -2486,6 +2555,7 @@ gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
wd->target_machine = m->target_machine;
wd->do_threading = false;
lb_llvm_module_pass_worker_proc(wd);
}
}
@@ -2566,31 +2636,6 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
}
gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
if (LLVM_IGNORE_VERIFICATION) {
return true;
}
if (do_threading) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
}
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
if (lb_llvm_module_verification_worker_proc(m)) {
return false;
}
}
}
return true;
}
gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
@@ -2686,8 +2731,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true);
params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true);
call_cleanup = false;
} else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) {
} else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) {
name = str_lit("mainCRTStartup");
} else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) {
// Windows i386 with CRT: libcmt expects _main (main with underscore prefix)
name = str_lit("main");
has_args = true;
slice_init(&params->Tuple.variables, permanent_allocator(), 2);
params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
} else if (is_arch_wasm()) {
name = str_lit("_start");
call_cleanup = false;
@@ -2813,16 +2865,19 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
}
gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
if (p->is_done) {
if (p->is_done.load(std::memory_order_relaxed)) {
return;
}
if (p->body != nullptr) { // Build Procedure
m->curr_procedure = p;
lb_begin_procedure_body(p);
lb_build_stmt(p, p->body);
lb_end_procedure_body(p);
p->is_done = true;
p->is_done.store(true, std::memory_order_relaxed);
m->curr_procedure = nullptr;
} else if (p->generate_body != nullptr) {
p->generate_body(m, p);
}
// Add Flags
@@ -2831,6 +2886,9 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
}
lb_verify_function(m, p, true);
MUTEX_GUARD(&m->generated_procedures_mutex);
array_add(&m->generated_procedures, p);
}
@@ -2845,8 +2903,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *default_module = &gen->default_module;
CheckerInfo *info = gen->info;
auto *min_dep_set = &info->minimum_dependency_set;
switch (build_context.metrics.arch) {
case TargetArch_amd64:
case TargetArch_i386:
@@ -3162,6 +3218,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
String link_name = e->Procedure.link_name;
if (e->pkg->kind == Package_Runtime) {
if (link_name == "main" ||
link_name == "_main" ||
link_name == "DllMain" ||
link_name == "WinMain" ||
link_name == "wWinMain" ||
@@ -3184,7 +3241,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
continue;
}
if (!ptr_set_exists(min_dep_set, e)) {
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
continue;
}
@@ -3194,47 +3251,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
GB_ASSERT(e->kind == Entity_Variable);
bool is_foreign = e->Variable.is_foreign;
bool is_export = e->Variable.is_export;
lbModule *default_module = &gen->default_module;
lbModule *m = default_module;
lbModule *e_module = lb_module_of_entity(gen, e, default_module);
bool const split_globals_across_modules = false;
if (split_globals_across_modules) {
m = e_module;
}
lbModule *m = &gen->default_module;
String name = lb_get_entity_name(m, e);
lbValue g = {};
g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
g.type = alloc_type_pointer(e->type);
lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
if (is_foreign) {
LLVMSetLinkage(g.value, LLVMExternalLinkage);
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
LLVMSetExternallyInitialized(g.value, true);
lb_add_foreign_library_path(m, e->Variable.foreign_library);
} else {
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
}
if (is_export) {
LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
} else if (!is_foreign) {
LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
}
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
if (e->Variable.link_section.len > 0) {
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
}
lbGlobalVariable var = {};
var.var = g;
var.decl = decl;
lbValue g = {};
g.type = alloc_type_pointer(e->type);
g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
if (decl->init_expr != nullptr) {
TypeAndValue tav = type_and_value_of_expr(decl->init_expr);
if (!is_type_any(e->type) && !is_type_union(e->type)) {
if (!is_type_any(e->type)) {
if (tav.mode != Addressing_Invalid) {
if (tav.value.kind != ExactValue_Invalid) {
auto cc = LB_CONST_CONTEXT_DEFAULT;
@@ -3244,6 +3286,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
ExactValue v = tav.value;
lbValue init = lb_const_value(m, tav.type, v, cc);
LLVMDeleteGlobal(g.value);
g.value = nullptr;
g.value = LLVMAddGlobal(m->mod, LLVMTypeOf(init.value), alloc_cstring(permanent_allocator(), name));
LLVMSetInitializer(g.value, init.value);
var.is_initialized = true;
if (cc.is_rodata) {
@@ -3262,16 +3309,33 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetGlobalConstant(g.value, true);
}
lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
if (is_foreign) {
LLVMSetLinkage(g.value, LLVMExternalLinkage);
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
LLVMSetExternallyInitialized(g.value, true);
lb_add_foreign_library_path(m, e->Variable.foreign_library);
} else if (LLVMGetInitializer(g.value) == nullptr) {
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
}
if (is_export) {
LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
} else if (!is_foreign) {
LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
}
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
if (e->Variable.link_section.len > 0) {
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
}
if (e->flags & EntityFlag_Require) {
lb_append_to_compiler_used(m, g.value);
}
array_add(&global_variables, var);
lb_add_entity(m, e, g);
lb_add_member(m, name, g);
if (m->debug_builder) {
String global_name = e->token.string;
if (global_name.len != 0 && global_name != "_") {
@@ -3300,6 +3364,27 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMGlobalSetMetadata(g.value, 0, global_variable_metadata);
}
}
if (default_module == m) {
g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type)));
var.var = g;
array_add(&global_variables, var);
} else {
lbValue local_g = {};
local_g.type = alloc_type_pointer(e->type);
local_g.value = LLVMAddGlobal(default_module->mod, lb_type(default_module, e->type), alloc_cstring(permanent_allocator(), name));
LLVMSetLinkage(local_g.value, LLVMExternalLinkage);
var.var = local_g;
array_add(&global_variables, var);
lb_add_entity(default_module, e, local_g);
lb_add_member(default_module, name, local_g);
}
lb_add_entity(m, e, g);
lb_add_member(m, name, g);
}
if (build_context.ODIN_DEBUG) {
@@ -3471,15 +3556,23 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
TIME_SECTION("LLVM Add Foreign Library Paths");
lb_add_foreign_library_paths(gen);
TIME_SECTION("LLVM Function Pass");
lb_llvm_function_passes(gen, do_threading && !build_context.ODIN_DEBUG);
TIME_SECTION("LLVM Module Pass");
lb_llvm_module_passes(gen, do_threading);
TIME_SECTION("LLVM Remove Unused Functions and Globals");
lb_remove_unused_functions_and_globals(gen);
TIME_SECTION("LLVM Module Verification");
if (!lb_llvm_module_verification(gen, do_threading)) {
return false;
TIME_SECTION("LLVM Module Pass and Verification");
lb_llvm_module_passes_and_verification(gen, do_threading);
TIME_SECTION("LLVM Correct Entity Linkage");
lb_correct_entity_linkage(gen);
if (build_context.build_diagnostics) {
lb_do_build_diagnostics(gen);
}
llvm_error = nullptr;
@@ -3508,11 +3601,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
TIME_SECTION("LLVM Add Foreign Library Paths");
lb_add_foreign_library_paths(gen);
TIME_SECTION("LLVM Correct Entity Linkage");
lb_correct_entity_linkage(gen);
////////////////////////////////////////////
for (auto const &entry: gen->modules) {
+30 -9
View File
@@ -147,9 +147,13 @@ struct lbModule {
LLVMModuleRef mod;
LLVMContextRef ctx;
Checker *checker;
struct lbGenerator *gen;
LLVMTargetMachineRef target_machine;
lbModule *polymorphic_module;
CheckerInfo *info;
AstPackage *pkg; // possibly associated
AstFile *file; // possibly associated
@@ -171,7 +175,8 @@ struct lbModule {
StringMap<lbValue> members;
StringMap<lbProcedure *> procedures;
PtrMap<LLVMValueRef, Entity *> procedure_values;
Array<lbProcedure *> missing_procedures_to_check;
MPSCQueue<lbProcedure *> missing_procedures_to_check;
StringMap<LLVMValueRef> const_strings;
String16Map<LLVMValueRef> const_string16s;
@@ -180,10 +185,13 @@ struct lbModule {
StringMap<lbProcedure *> gen_procs; // key is the canonicalized name
Array<lbProcedure *> procedures_to_generate;
MPSCQueue<lbProcedure *> procedures_to_generate;
Array<Entity *> global_procedures_to_create;
Array<Entity *> global_types_to_create;
BlockingMutex generated_procedures_mutex;
Array<lbProcedure *> generated_procedures;
lbProcedure *curr_procedure;
LLVMBuilderRef const_dummy_builder;
@@ -232,8 +240,7 @@ struct lbGenerator : LinkerData {
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
lbModule default_module;
RecursiveMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
lbModule *equal_module;
isize used_module_count;
@@ -329,6 +336,14 @@ struct lbVariadicReuseSlices {
lbAddr slice_addr;
};
struct lbGlobalVariable {
lbValue var;
lbValue init;
DeclInfo *decl;
bool is_initialized;
};
struct lbProcedure {
u32 flags;
u16 state_flags;
@@ -351,9 +366,9 @@ struct lbProcedure {
lbFunctionType *abi_function_type;
LLVMValueRef value;
LLVMBuilderRef builder;
bool is_done;
LLVMValueRef value;
LLVMBuilderRef builder;
std::atomic<bool> is_done;
lbAddr return_ptr;
Array<lbDefer> defer_stmts;
@@ -391,6 +406,12 @@ struct lbProcedure {
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;
Array<lbValue> asan_stack_locals;
void (*generate_body)(lbModule *m, lbProcedure *p);
Array<lbGlobalVariable> *global_variables;
lbProcedure *objc_names;
Type *internal_gen_type; // map_set, map_get, etc.
};
@@ -434,7 +455,7 @@ static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, {
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT);
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT, Type *value_type=nullptr);
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
@@ -583,7 +604,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
+240 -63
View File
@@ -81,7 +81,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value) {
}
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst, bool *failure_) {
LLVMTypeRef src = LLVMTypeOf(val);
if (src == dst) {
return val;
@@ -96,15 +96,12 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
case LLVMPointerTypeKind:
return LLVMConstPointerCast(val, dst);
case LLVMStructTypeKind:
// GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst));
// NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place?
// It seems mostly to exist to get around the "anonymous -> named" struct assignments
// return LLVMConstBitCast(val, dst);
if (LLVMTypeOf(val) != dst) {
if (failure_) *failure_ = true;
}
return val;
default:
GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
}
if (failure_) *failure_ = true;
return val;
}
@@ -129,13 +126,13 @@ gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMVa
LLVMConstNull(lb_type(m, t_i32)),
len,
};
return llvm_const_named_struct_internal(lb_type(m, t), values, 3);
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3);
} else {
LLVMValueRef values[2] = {
data,
len,
};
return llvm_const_named_struct_internal(lb_type(m, t), values, 2);
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2);
}
}
@@ -147,13 +144,13 @@ gb_internal LLVMValueRef llvm_const_string16_internal(lbModule *m, Type *t, LLVM
LLVMConstNull(lb_type(m, t_i32)),
len,
};
return llvm_const_named_struct_internal(lb_type(m, t), values, 3);
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3);
} else {
LLVMValueRef values[2] = {
data,
len,
};
return llvm_const_named_struct_internal(lb_type(m, t), values, 2);
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2);
}
}
@@ -165,10 +162,10 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
unsigned value_count = cast(unsigned)value_count_;
unsigned elem_count = LLVMCountStructElementTypes(struct_type);
if (elem_count == value_count) {
return llvm_const_named_struct_internal(struct_type, values, value_count_);
return llvm_const_named_struct_internal(m, struct_type, values, value_count_);
}
Type *bt = base_type(t);
GB_ASSERT(bt->kind == Type_Struct);
GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union);
GB_ASSERT(value_count_ == bt->Struct.fields.count);
@@ -185,25 +182,40 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
}
}
return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count);
return llvm_const_named_struct_internal(m, struct_type, values_with_padding, values_with_padding_count);
}
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
unsigned elem_count = LLVMCountStructElementTypes(t);
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
bool failure = false;
for (unsigned i = 0; i < elem_count; i++) {
LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i);
values[i] = llvm_const_cast(values[i], elem_type);
values[i] = llvm_const_cast(values[i], elem_type, &failure);
}
if (failure) {
return LLVMConstStructInContext(m->ctx, values, value_count, true);
}
return LLVMConstNamedStruct(t, values, value_count);
}
gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
gb_internal LLVMValueRef llvm_const_array(lbModule *m, LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
bool failure = false;
for (unsigned i = 0; i < value_count; i++) {
values[i] = llvm_const_cast(values[i], elem_type);
values[i] = llvm_const_cast(values[i], elem_type, &failure);
}
if (failure) {
return LLVMConstStructInContext(m->ctx, values, value_count, false);
}
for (unsigned i = 0; i < value_count; i++) {
if (elem_type != LLVMTypeOf(values[i])) {
return LLVMConstStructInContext(m->ctx, values, value_count, false);
}
}
return LLVMConstArray(elem_type, values, value_count);
}
@@ -461,7 +473,7 @@ gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type,
return lb_addr_load(p, v).value;
}
return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
return llvm_const_array(m, lb_type(m, elem_type), values, cast(unsigned int)count);
}
gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
@@ -531,13 +543,13 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel,
}
if (is_type_raw_union(ft) || is_type_typeid(ft)) {
if (is_type_raw_union(ft)) {
return false;
}
return lb_is_elem_const(elem, ft);
}
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) {
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) {
if (cc.allow_local) {
cc.is_rodata = false;
}
@@ -552,12 +564,101 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
type = core_type(type);
value = convert_exact_value_for_type(value, type);
if (value.kind == ExactValue_Typeid) {
return lb_typeid(m, value.value_typeid);
}
bool is_local = cc.allow_local && m->curr_procedure != nullptr;
if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, original_type);
if (is_type_union(type) && is_type_union_constantable(type)) {
Type *bt = base_type(type);
GB_ASSERT(bt->kind == Type_Union);
if (bt->Union.variants.count == 0) {
return lb_const_nil(m, original_type);
} else if (bt->Union.variants.count == 1) {
Type *t = bt->Union.variants[0];
lbValue cv = lb_const_value(m, t, value, cc);
GB_ASSERT(LLVMIsConstant(cv.value));
LLVMTypeRef llvm_type = lb_type(m, original_type);
if (is_type_union_maybe_pointer(type)) {
LLVMValueRef values[1] = {cv.value};
res.value = llvm_const_named_struct_internal(m, llvm_type, values, 1);
res.type = original_type;
return res;
} else {
unsigned tag_value = 1;
if (bt->Union.kind == UnionType_no_nil) {
tag_value = 0;
}
LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false);
LLVMValueRef padding = nullptr;
LLVMValueRef values[3] = {cv.value, tag, padding};
isize value_count = 2;
if (LLVMCountStructElementTypes(llvm_type) > 2) {
value_count = 3;
padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2));
}
res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count);
res.type = original_type;
return res;
}
} else {
if (value_type == nullptr) {
if (value.kind == ExactValue_Compound) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
return lb_const_nil(m, original_type);
}
} else if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, original_type);
}
}
GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value));
i64 block_size = bt->Union.variant_block_size;
if (are_types_identical(value_type, original_type)) {
if (value.kind == ExactValue_Compound) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
return lb_const_nil(m, original_type);
}
} else if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, original_type);
}
GB_PANIC("%s vs %s", type_to_string(value_type), type_to_string(original_type));
}
lbValue cv = lb_const_value(m, value_type, value, cc, value_type);
Type *variant_type = cv.type;
LLVMValueRef values[4] = {};
unsigned value_count = 0;
values[value_count++] = cv.value;
if (type_size_of(variant_type) != block_size) {
LLVMTypeRef padding_type = lb_type_padding_filler(m, block_size - type_size_of(variant_type), 1);
values[value_count++] = LLVMConstNull(padding_type);
}
Type *tag_type = union_tag_type(bt);
LLVMTypeRef llvm_tag_type = lb_type(m, tag_type);
i64 tag_index = union_variant_index(bt, variant_type);
GB_ASSERT(tag_index >= 0);
values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false);
i64 used_size = block_size + type_size_of(tag_type);
i64 union_size = type_size_of(bt);
i64 padding = union_size - used_size;
if (padding > 0) {
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, 1);
values[value_count++] = LLVMConstNull(padding_type);
}
res.value = LLVMConstStructInContext(m->ctx, values, value_count, true);
return res;
}
}
if (value.kind == ExactValue_Procedure) {
@@ -583,7 +684,23 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
return res;
}
bool is_local = cc.allow_local && m->curr_procedure != nullptr;
// NOTE(bill): This has to be done AFTER the union stuff
if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, original_type);
}
if (value.kind == ExactValue_Typeid) {
return lb_typeid(m, value.value_typeid);
}
if (value.kind == ExactValue_Compound) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
return lb_const_nil(m, original_type);
}
}
// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
@@ -596,7 +713,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
GB_ASSERT(is_type_slice(type));
res.value = lb_find_or_add_entity_string16_slice_with_type(m, value.value_string16, original_type).value;
return res;
}else {
} else {
ast_node(cl, CompoundLit, value.value_compound);
isize count = cl->elems.count;
@@ -606,19 +723,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc);
lbValue backing_array = lb_const_value(m, t, value, cc, nullptr);
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;
LLVMTypeRef llvm_type = lb_type(m, t);
array_data = llvm_alloca(p, llvm_type, 16);
unsigned alignment = cast(unsigned)gb_max(type_align_of(t), 16);
bool do_local_copy = false;
if (do_local_copy) {
array_data = llvm_alloca(p, llvm_type, alignment);
LLVMValueRef local_copy = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment);
LLVMBuildStore(p->builder, backing_array.value, local_copy);
LLVMBuildMemCpy(p->builder,
array_data, alignment,
local_copy, alignment,
LLVMConstInt(lb_type(m, t_int), type_size_of(t), false)
);
} else {
array_data = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment);
LLVMBuildStore(p->builder, backing_array.value, array_data);
array_data = LLVMBuildPointerCast(p->builder, array_data, LLVMPointerType(llvm_type, 0), "");
}
LLVMBuildStore(p->builder, backing_array.value, array_data);
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
@@ -640,7 +777,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
String name = make_string(cast(u8 const *)str, gb_string_length(str));
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str);
array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str);
LLVMSetInitializer(array_data, backing_array.value);
if (cc.link_section.len > 0) {
@@ -651,15 +788,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
lbValue g = {};
g.value = array_data;
g.value = LLVMConstPointerCast(array_data, LLVMPointerType(lb_type(m, t), 0));
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 = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2);
LLVMValueRef ptr = g.value;
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
LLVMValueRef values[2] = {ptr, len};
@@ -692,7 +828,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
GB_ASSERT(offset == s.len);
res.value = llvm_const_array(et, elems, cast(unsigned)count);
res.value = llvm_const_array(m, et, elems, cast(unsigned)count);
return res;
}
// NOTE(bill, 2021-10-07): Allow for array programming value constants
@@ -722,7 +858,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
elems[i] = single_elem.value;
}
res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count);
res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count);
return res;
} else if (is_type_matrix(type) &&
value.kind != ExactValue_Invalid &&
@@ -734,7 +870,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
Type *elem = type->Matrix.elem;
lbValue single_elem = lb_const_value(m, elem, value, cc);
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
i64 total_elem_count = matrix_type_total_internal_elems(type);
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)total_elem_count);
@@ -756,7 +892,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
Type *elem = type->SimdVector.elem;
lbValue single_elem = lb_const_value(m, elem, value, cc);
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count);
for (i64 i = 0; i < count; i++) {
@@ -981,7 +1117,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
for (i64 k = lo; k < hi; k++) {
aos_values[value_index++] = val;
}
@@ -996,7 +1132,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
aos_values[value_index++] = val;
found = true;
break;
@@ -1049,7 +1185,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
}
for (isize i = elem_count; i < type->Struct.soa_count; i++) {
aos_values[i] = nullptr;
@@ -1116,7 +1252,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -1131,7 +1267,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
values[value_index++] = val;
found = true;
break;
@@ -1146,12 +1282,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else if (value.value_compound->tav.type == elem_type) {
} else if (are_types_identical(value.value_compound->tav.type, elem_type)) {
// Compound is of array item type; expand its value to all items in array.
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
for (isize i = 0; i < type->Array.count; i++) {
values[i] = lb_const_value(m, elem_type, value, cc).value;
values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value;
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
@@ -1165,7 +1301,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
}
for (isize i = elem_count; i < type->Array.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
@@ -1211,7 +1347,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -1226,7 +1362,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
values[value_index++] = val;
found = true;
break;
@@ -1249,7 +1385,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
}
for (isize i = elem_count; i < type->EnumeratedArray.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
@@ -1294,7 +1430,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -1309,7 +1445,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
values[value_index++] = val;
found = true;
break;
@@ -1328,7 +1464,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
}
LLVMTypeRef et = lb_type(m, elem_type);
@@ -1336,7 +1472,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
values[i] = LLVMConstNull(et);
}
for (isize i = 0; i < total_elem_count; i++) {
values[i] = llvm_const_cast(values[i], et);
values[i] = llvm_const_cast(values[i], et, /*failure_*/nullptr);
}
res.value = LLVMConstVector(values, cast(unsigned)total_elem_count);
@@ -1350,6 +1486,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (is_type_raw_union(type)) {
if (is_type_raw_union_constantable(type)) {
GB_ASSERT(cl->elems.count == 1);
GB_ASSERT(cl->elems[0]->kind == Ast_FieldValue);
ast_node(fv, FieldValue, cl->elems[0]);
Entity *f = entity_of_node(fv->field);
TypeAndValue tav = fv->value->tav;
if (tav.value.kind != ExactValue_Invalid) {
lbValue value = lb_const_value(m, f->type, tav.value, cc, f->type);
LLVMValueRef values[2];
unsigned value_count = 0;
values[value_count++] = value.value;
i64 union_alignment = type_align_of(type);
i64 value_alignment = type_align_of(f->type);
i64 alignment = gb_max(gb_min(value_alignment, union_alignment), 1);
i64 union_size = type_size_of(type);
i64 value_size = lb_sizeof(LLVMTypeOf(value.value));
i64 padding = union_size-value_size;
if (padding > 0) {
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, alignment);
values[value_count++] = LLVMConstNull(padding_type);
}
LLVMValueRef res = LLVMConstStructInContext(m->ctx, values, value_count, /*packed*/padding > 0);
return {res, original_type};
}
}
return lb_const_nil(m, original_type);
}
@@ -1377,7 +1546,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type);
LLVMTypeRef value_type = LLVMTypeOf(value.value);
GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type));
values[index] = value.value;
visited[index] = true;
} else {
if (!visited[index]) {
@@ -1423,7 +1595,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
}
if (is_constant) {
LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).value;
LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc, tav.type).value;
if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) {
values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len);
} else if (is_local) {
@@ -1477,7 +1649,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
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, cc).value;
lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type);
LLVMTypeRef value_type = LLVMTypeOf(value.value);
GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type));
values[index] = value.value;
visited[index] = true;
}
}
@@ -1503,7 +1678,9 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (is_constant) {
res.value = llvm_const_named_struct_internal(struct_type, values, cast(unsigned)value_count);
res.value = llvm_const_named_struct_internal(m, struct_type, values, cast(unsigned)value_count);
LLVMTypeRef res_type = LLVMTypeOf(res.value);
GB_ASSERT(lb_sizeof(res_type) == lb_sizeof(struct_type));
return res;
} else {
// TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED
@@ -1517,7 +1694,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
new_values[i] = LLVMConstNull(LLVMTypeOf(old_value));
}
}
LLVMValueRef constant_value = llvm_const_named_struct_internal(struct_type, new_values, cast(unsigned)value_count);
LLVMValueRef constant_value = llvm_const_named_struct_internal(m, struct_type, new_values, cast(unsigned)value_count);
GB_ASSERT(is_local);
lbProcedure *p = m->curr_procedure;
@@ -1611,7 +1788,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
for (i64 k = lo; k < hi; k++) {
i64 offset = matrix_row_major_index_to_offset(type, k);
GB_ASSERT(values[offset] == nullptr);
@@ -1623,7 +1800,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
i64 index = exact_value_to_i64(index_tav.value);
GB_ASSERT(index < max_count);
TypeAndValue tav = fv->value->tav;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
i64 offset = matrix_row_major_index_to_offset(type, index);
GB_ASSERT(values[offset] == nullptr);
values[offset] = val;
@@ -1647,7 +1824,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
GB_ASSERT(tav.mode != Addressing_Invalid);
i64 offset = 0;
offset = matrix_row_major_index_to_offset(type, i);
values[offset] = lb_const_value(m, elem_type, tav.value, cc).value;
values[offset] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
}
for (isize i = 0; i < total_count; i++) {
if (values[i] == nullptr) {
+1 -1
View File
@@ -1327,7 +1327,7 @@ gb_internal void lb_add_debug_info_for_global_constant_from_entity(lbGenerator *
}
lbModule *m = &gen->default_module;
if (USE_SEPARATE_MODULES) {
m = lb_module_of_entity(gen, e);
m = lb_module_of_entity(gen, e, m);
}
GB_ASSERT(m != nullptr);
+22 -6
View File
@@ -2502,7 +2502,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
for (Type *vt : dst->Union.variants) {
if (src_type == t_llvm_bool && is_type_boolean(vt)) {
value = lb_emit_conv(p, value, vt);
lbAddr parent = lb_add_local_generated(p, t, true);
lb_emit_store_union_variant(p, parent.addr, value, vt);
return lb_addr_load(p, parent);
@@ -2563,10 +2562,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
Type *dt = t;
TEMPORARY_ALLOCATOR_GUARD();
GB_ASSERT(is_type_struct(st) || is_type_raw_union(st));
Selection sel = {};
sel.index.allocator = heap_allocator();
defer (array_free(&sel.index));
sel.index.allocator = temporary_allocator();
if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) {
if (sel.entity == nullptr) {
GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t));
@@ -3929,6 +3929,20 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
return res;
}
gb_internal Type *lb_build_expr_original_const_type(Ast *expr) {
expr = unparen_expr(expr);
Type *type = type_of_expr(expr);
if (is_type_union(type)) {
if (expr->kind == Ast_CallExpr) {
if (expr->CallExpr.proc->tav.mode == Addressing_Type) {
Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]);
return res;
}
}
}
return type_of_expr(expr);
}
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
lbModule *m = p->module;
@@ -3940,9 +3954,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type));
if (tv.value.kind != ExactValue_Invalid) {
Type *original_type = lb_build_expr_original_const_type(expr);
// NOTE(bill): Short on constant values
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, original_type);
} else if (tv.mode == Addressing_Type) {
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
return lb_typeid(m, tv.type);
@@ -4023,7 +4039,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
TypeAndValue tav = type_and_value_of_expr(expr);
GB_ASSERT(tav.mode == Addressing_Constant);
return lb_const_value(p->module, type, tv.value);
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, tv.type);
case_end;
case_ast_node(se, SelectorCallExpr, expr);
@@ -4304,7 +4320,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp
GB_ASSERT(e != nullptr);
if (e->kind == Entity_Constant) {
Type *t = default_type(type_of_expr(expr));
lbValue v = lb_const_value(p->module, t, e->Constant.value);
lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL, e->type);
if (LLVMIsConstant(v.value)) {
lbAddr g = lb_add_global_generated_from_procedure(p, t, v);
return g;
+279 -62
View File
@@ -15,7 +15,9 @@ gb_global isize lb_global_type_info_member_offsets_index = 0;
gb_global isize lb_global_type_info_member_usings_index = 0;
gb_global isize lb_global_type_info_member_tags_index = 0;
gb_internal void lb_init_module(lbModule *m, Checker *c) {
gb_internal WORKER_TASK_PROC(lb_init_module_worker_proc) {
lbModule *m = cast(lbModule *)data;
Checker *c = m->checker;
m->info = &c->info;
@@ -46,6 +48,12 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
}
module_name = gb_string_appendc(module_name, "builtin");
}
if (m->polymorphic_module == m) {
if (gb_string_length(module_name)) {
module_name = gb_string_appendc(module_name, "-");
}
module_name = gb_string_appendc(module_name, "$parapoly");
}
m->module_name = module_name;
m->ctx = LLVMContextCreate();
@@ -89,15 +97,19 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
map_init(&m->function_type_map);
string_map_init(&m->gen_procs);
if (USE_SEPARATE_MODULES) {
array_init(&m->procedures_to_generate, a, 0, 1<<10);
mpsc_init(&m->procedures_to_generate, a);
map_init(&m->procedure_values, 1<<11);
array_init(&m->generated_procedures, a, 0, 1<<10);
} else {
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
mpsc_init(&m->procedures_to_generate, a);
map_init(&m->procedure_values, c->info.all_procedures.count*2);
array_init(&m->generated_procedures, a, 0, c->info.all_procedures.count*2);
}
array_init(&m->global_procedures_to_create, a, 0, 1024);
array_init(&m->global_types_to_create, a, 0, 1024);
array_init(&m->missing_procedures_to_check, a, 0, 16);
mpsc_init(&m->missing_procedures_to_check, a);
map_init(&m->debug_values);
string_map_init(&m->objc_classes);
@@ -113,6 +125,15 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
m->const_dummy_builder = LLVMCreateBuilderInContext(m->ctx);
return 0;
}
gb_internal void lb_init_module(lbModule *m, bool do_threading) {
if (do_threading) {
thread_pool_add_task(lb_init_module_worker_proc, m);
} else {
lb_init_module_worker_proc(m);
}
}
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
@@ -125,6 +146,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
return false;
}
isize thread_count = gb_max(build_context.thread_count, 1);
isize worker_count = thread_count-1;
bool do_threading = !!(LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0);
String init_fullpath = c->parser->init_fullpath;
linker_data_init(gen, &c->info, init_fullpath);
@@ -136,7 +161,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
map_init(&gen->modules, gen->info->packages.count*2);
map_init(&gen->modules_through_ctx, gen->info->packages.count*2);
map_init(&gen->anonymous_proc_lits, 1024);
if (USE_SEPARATE_MODULES) {
bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0;
@@ -145,26 +169,94 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
auto m = gb_alloc_item(permanent_allocator(), lbModule);
m->pkg = pkg;
m->gen = gen;
m->checker = c;
map_set(&gen->modules, cast(void *)pkg, m);
lb_init_module(m, c);
if (!module_per_file) {
lb_init_module(m, do_threading);
if (LLVM_WEAK_MONOMORPHIZATION) {
auto pm = gb_alloc_item(permanent_allocator(), lbModule);
pm->pkg = pkg;
pm->gen = gen;
pm->checker = c;
m->polymorphic_module = pm;
pm->polymorphic_module = pm;
map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list
lb_init_module(pm, do_threading);
}
bool allow_for_per_file = pkg->kind == Package_Runtime || module_per_file;
#if 0
if (!allow_for_per_file) {
if (pkg->files.count >= 20) {
isize proc_count = 0;
for (Entity *e : gen->info->entities) {
if (e->kind != Entity_Procedure) {
continue;
}
if (e->Procedure.is_foreign) {
continue;
}
if (e->pkg == pkg) {
proc_count += 1;
}
}
if (proc_count >= 300) {
allow_for_per_file = true;
}
}
}
#endif
if (!allow_for_per_file) {
continue;
}
// NOTE(bill): Probably per file is not a good idea, so leave this for later
for (AstFile *file : pkg->files) {
auto m = gb_alloc_item(permanent_allocator(), lbModule);
auto m = gb_alloc_item(permanent_allocator(), lbModule);
m->file = file;
m->pkg = pkg;
m->gen = gen;
m->pkg = pkg;
m->gen = gen;
m->checker = c;
map_set(&gen->modules, cast(void *)file, m);
lb_init_module(m, c);
lb_init_module(m, do_threading);
if (LLVM_WEAK_MONOMORPHIZATION) {
auto pm = gb_alloc_item(permanent_allocator(), lbModule);
pm->file = file;
pm->pkg = pkg;
pm->gen = gen;
pm->checker = c;
m->polymorphic_module = pm;
pm->polymorphic_module = pm;
map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list
lb_init_module(pm, do_threading);
}
}
}
if (LLVM_WEAK_MONOMORPHIZATION) {
lbModule *m = gb_alloc_item(permanent_allocator(), lbModule);
gen->equal_module = m;
m->gen = gen;
m->checker = c;
map_set(&gen->modules, cast(void *)m, m); // point to itself just add it to the list
lb_init_module(m, do_threading);
}
}
gen->default_module.gen = gen;
gen->default_module.checker = c;
map_set(&gen->modules, cast(void *)1, &gen->default_module);
lb_init_module(&gen->default_module, c);
lb_init_module(&gen->default_module, do_threading);
thread_pool_wait();
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
@@ -403,9 +495,9 @@ gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) {
return &gen->default_module;
}
gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
GB_ASSERT(e != nullptr);
gb_internal lbModule *lb_module_of_entity_internal(lbGenerator *gen, Entity *e, lbModule *curr_module) {
lbModule **found = nullptr;
if (e->kind == Entity_Procedure &&
e->decl_info &&
e->decl_info->code_gen_module) {
@@ -428,6 +520,22 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
return &gen->default_module;
}
gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e, lbModule *curr_module) {
GB_ASSERT(e != nullptr);
GB_ASSERT(curr_module != nullptr);
lbModule *m = lb_module_of_entity_internal(gen, e, curr_module);
if (USE_SEPARATE_MODULES) {
if (e->kind == Entity_Procedure && e->Procedure.generated_from_polymorphic) {
if (m->polymorphic_module) {
return m->polymorphic_module;
}
}
}
return m;
}
gb_internal lbAddr lb_addr(lbValue addr) {
lbAddr v = {lbAddr_Default, addr};
return v;
@@ -1408,8 +1516,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
unsigned element_count = LLVMCountStructElementTypes(uvt);
GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
LLVMValueRef ptr = u.value;
ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), "");
lbValue tag_ptr = {};
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, "");
tag_ptr.type = alloc_type_pointer(tag_type);
return tag_ptr;
}
@@ -1634,8 +1745,92 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t
map_set(&m->func_raw_types, type, new_abi_fn_type);
return new_abi_fn_type;
}
gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *type) {
GB_ASSERT(type->kind == Type_Union);
if (type->Union.variants.count <= 0) {
return nullptr;
}
if (type->Union.variants.count == 1) {
return lb_type(m, type->Union.variants[0]);
}
i64 align = type_align_of(type);
unsigned block_size = cast(unsigned)type->Union.variant_block_size;
if (block_size == 0) {
return lb_type_padding_filler(m, block_size, align);
}
bool all_pointers = align == build_context.ptr_size;
for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) {
Type *t = type->Union.variants[i];
if (!is_type_internally_pointer_like(t)) {
all_pointers = false;
}
}
if (all_pointers) {
return lb_type(m, t_rawptr);
}
{
Type *pt = type->Union.variants[0];
for (isize i = 1; i < type->Union.variants.count; i++) {
Type *t = type->Union.variants[i];
if (!are_types_identical(pt, t)) {
goto end_check_for_all_the_same;
}
}
return lb_type(m, pt);
} end_check_for_all_the_same:;
{
Type *first_different = nullptr;
for (isize i = 0; i < type->Union.variants.count; i++) {
Type *t = type->Union.variants[i];
if (type_size_of(t) == 0) {
continue;
}
if (first_different == nullptr) {
first_different = t;
} else if (!are_types_identical(first_different, t)) {
goto end_rest_zero_except_one;
}
}
if (first_different != nullptr) {
return lb_type(m, first_different);
}
} end_rest_zero_except_one:;
// {
// LLVMTypeRef first_different = nullptr;
// for (isize i = 0; i < type->Union.variants.count; i++) {
// Type *t = type->Union.variants[i];
// if (type_size_of(t) == 0) {
// continue;
// }
// if (first_different == nullptr) {
// first_different = lb_type(m, base_type(t));
// } else {
// LLVMTypeRef llvm_t = lb_type(m, base_type(t));
// if (llvm_t != first_different) {
// goto end_rest_zero_except_one_llvm_like;
// }
// }
// }
// if (first_different != nullptr) {
// return first_different;
// }
// } end_rest_zero_except_one_llvm_like:;
return lb_type_padding_filler(m, block_size, align);
}
gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size
@@ -2148,27 +2343,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
}
unsigned block_size = cast(unsigned)type->Union.variant_block_size;
auto fields = array_make<LLVMTypeRef>(temporary_allocator(), 0, 3);
if (is_type_union_maybe_pointer(type)) {
LLVMTypeRef variant = lb_type(m, type->Union.variants[0]);
array_add(&fields, variant);
} else {
LLVMTypeRef block_type = nullptr;
} else if (type->Union.variants.count == 1) {
LLVMTypeRef block_type = lb_type(m, type->Union.variants[0]);
bool all_pointers = align == build_context.ptr_size;
for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) {
Type *t = type->Union.variants[i];
if (!is_type_internally_pointer_like(t)) {
all_pointers = false;
}
}
if (all_pointers) {
block_type = lb_type(m, t_rawptr);
} else {
block_type = lb_type_padding_filler(m, block_size, align);
LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
array_add(&fields, block_type);
array_add(&fields, tag_type);
i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type);
i64 padding = size - used_size;
if (padding > 0) {
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align);
array_add(&fields, padding_type);
}
} else {
LLVMTypeRef block_type = lb_type_internal_union_block_type(m, type);
LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
array_add(&fields, block_type);
@@ -2914,7 +3106,7 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e
return lb_find_procedure_value_from_entity(m, e);
}
if (USE_SEPARATE_MODULES) {
lbModule *other_module = lb_module_of_entity(m->gen, e);
lbModule *other_module = lb_module_of_entity(m->gen, e, m);
if (other_module != m) {
String name = lb_get_entity_name(other_module, e);
@@ -2962,7 +3154,7 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
lbModule *other_module = m;
if (USE_SEPARATE_MODULES) {
other_module = lb_module_of_entity(gen, e);
other_module = lb_module_of_entity(gen, e, m);
}
if (other_module == m) {
debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s module %p\n", LIT(e->token.string), m);
@@ -2979,9 +3171,6 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
}
if (ignore_body) {
mutex_lock(&gen->anonymous_proc_lits_mutex);
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
GB_ASSERT(other_module != nullptr);
rw_mutex_shared_lock(&other_module->values_mutex);
auto *found = map_get(&other_module->values, e);
@@ -2989,10 +3178,10 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
if (found == nullptr) {
// THIS IS THE RACE CONDITION
lbProcedure *missing_proc_in_other_module = lb_create_procedure(other_module, e, false);
array_add(&other_module->missing_procedures_to_check, missing_proc_in_other_module);
mpsc_enqueue(&other_module->missing_procedures_to_check, missing_proc_in_other_module);
}
} else {
array_add(&m->missing_procedures_to_check, missing_proc);
mpsc_enqueue(&m->missing_procedures_to_check, missing_proc);
}
rw_mutex_shared_lock(&m->values_mutex);
@@ -3010,18 +3199,16 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) {
lbGenerator *gen = m->gen;
mutex_lock(&gen->anonymous_proc_lits_mutex);
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
TokenPos pos = ast_token(expr).pos;
lbProcedure **found = map_get(&gen->anonymous_proc_lits, expr);
if (found) {
return lb_find_procedure_value_from_entity(m, (*found)->entity);
}
gb_unused(gen);
ast_node(pl, ProcLit, expr);
if (pl->decl->entity.load() != nullptr) {
return lb_find_procedure_value_from_entity(m, pl->decl->entity.load());
}
TokenPos pos = ast_token(expr).pos;
// NOTE(bill): Generate a new name
// parent$count
isize name_len = prefix_name.len + 6 + 11;
@@ -3039,30 +3226,51 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
token.string = name;
Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags);
e->file = expr->file();
e->scope = e->file->scope;
lbModule *target_module = m;
GB_ASSERT(target_module != nullptr);
// NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time
pl->decl->code_gen_module = m;
pl->decl->code_gen_module = target_module;
e->decl_info = pl->decl;
pl->decl->entity = e;
e->parent_proc_decl = pl->decl->parent;
e->Procedure.is_anonymous = true;
e->flags |= EntityFlag_ProcBodyChecked;
lbProcedure *p = lb_create_procedure(m, e);
GB_ASSERT(e->code_gen_module == m);
pl->decl->entity.store(e);
lbValue value = {};
value.value = p->value;
value.type = p->type;
map_set(&gen->anonymous_proc_lits, expr, p);
array_add(&m->procedures_to_generate, p);
if (parent != nullptr) {
array_add(&parent->children, p);
if (target_module != m) {
rw_mutex_shared_lock(&target_module->values_mutex);
lbValue *found = map_get(&target_module->values, e);
rw_mutex_shared_unlock(&target_module->values_mutex);
if (found == nullptr) {
lbProcedure *missing_proc_in_target_module = lb_create_procedure(target_module, e, false);
mpsc_enqueue(&target_module->missing_procedures_to_check, missing_proc_in_target_module);
}
lbProcedure *p = lb_create_procedure(m, e, true);
lbValue value = {};
value.value = p->value;
value.type = p->type;
return value;
} else {
string_map_set(&m->members, name, value);
lbProcedure *p = lb_create_procedure(m, e);
lbValue value = {};
value.value = p->value;
value.type = p->type;
mpsc_enqueue(&m->procedures_to_generate, p);
if (parent != nullptr) {
array_add(&parent->children, p);
} else {
string_map_set(&m->members, name, value);
}
return value;
}
return value;
}
@@ -3071,11 +3279,18 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
GB_ASSERT(type != nullptr);
type = default_type(type);
LLVMTypeRef actual_type = lb_type(m, type);
if (value.value != nullptr) {
LLVMTypeRef value_type = LLVMTypeOf(value.value);
GB_ASSERT_MSG(lb_sizeof(actual_type) == lb_sizeof(value_type), "%s vs %s", LLVMPrintTypeToString(actual_type), LLVMPrintTypeToString(value_type));
actual_type = value_type;
}
Scope *scope = nullptr;
Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
lbValue g = {};
g.type = alloc_type_pointer(type);
g.value = LLVMAddGlobal(m->mod, lb_type(m, type), alloc_cstring(temporary_allocator(), name));
g.value = LLVMAddGlobal(m->mod, actual_type, alloc_cstring(temporary_allocator(), name));
if (value.value != nullptr) {
GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value));
LLVMSetInitializer(g.value, value.value);
@@ -3083,6 +3298,8 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type)));
}
g.value = LLVMConstPointerCast(g.value, lb_type(m, g.type));
lb_add_entity(m, e, g);
lb_add_member(m, name, g);
@@ -3145,7 +3362,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
}
if (USE_SEPARATE_MODULES) {
lbModule *other_module = lb_module_of_entity(m->gen, e);
lbModule *other_module = lb_module_of_entity(m->gen, e, m);
bool is_external = other_module != m;
if (!is_external) {
+13 -14
View File
@@ -84,7 +84,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
String link_name = {};
if (ignore_body) {
lbModule *other_module = lb_module_of_entity(m->gen, entity);
lbModule *other_module = lb_module_of_entity(m->gen, entity, m);
link_name = lb_get_entity_name(other_module, entity);
} else {
link_name = lb_get_entity_name(m, entity);
@@ -99,7 +99,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
}
}
lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure);
p->module = m;
@@ -837,9 +836,8 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
GB_ASSERT(pd->body != nullptr);
lbModule *m = p->module;
auto *min_dep_set = &m->info->minimum_dependency_set;
if (ptr_set_exists(min_dep_set, e) == false) {
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
return;
}
@@ -875,7 +873,7 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e)
lb_add_entity(m, e, value);
array_add(&p->children, nested_proc);
array_add(&m->procedures_to_generate, nested_proc);
mpsc_enqueue(&m->procedures_to_generate, nested_proc);
}
@@ -962,13 +960,14 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue
arg_type != param_type) {
LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type);
LLVMTypeKind param_kind = LLVMGetTypeKind(param_type);
if (arg_kind == param_kind &&
arg_kind == LLVMPointerTypeKind) {
// NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times
// I don't know why...
args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, "");
arg_type = param_type;
continue;
if (arg_kind == param_kind) {
if (arg_kind == LLVMPointerTypeKind) {
// NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times
// I don't know why...
args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, "");
arg_type = param_type;
continue;
}
}
}
@@ -2251,7 +2250,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
GB_ASSERT(e != nullptr);
if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) {
procedure = e->parent_proc_decl->entity->token.string;
procedure = e->parent_proc_decl->entity.load()->token.string;
} else {
procedure = str_lit("");
}
@@ -2278,7 +2277,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
elements[i] = element;
}
LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
LLVMValueRef backing_array = llvm_const_array(m, lb_type(m, t_load_directory_file), elements, count);
Type *array_type = alloc_type_array(t_load_directory_file, count);
lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type});
+3 -5
View File
@@ -3,8 +3,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
return;
}
auto *min_dep_set = &p->module->info->minimum_dependency_set;
for (Ast *ident : vd->names) {
GB_ASSERT(ident->kind == Ast_Ident);
Entity *e = entity_of_node(ident);
@@ -21,7 +19,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
}
}
if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) {
continue;
}
@@ -56,7 +54,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
if (gpd) {
rw_mutex_shared_lock(&gpd->mutex);
for (Entity *e : gpd->procs) {
if (!ptr_set_exists(min_dep_set, e)) {
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
continue;
}
DeclInfo *d = decl_info_of_entity(e);
@@ -94,7 +92,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
value.value = nested_proc->value;
value.type = nested_proc->type;
array_add(&p->module->procedures_to_generate, nested_proc);
mpsc_enqueue(&p->module->procedures_to_generate, nested_proc);
array_add(&p->children, nested_proc);
string_map_set(&p->module->members, name, value);
}
+6 -5
View File
@@ -302,7 +302,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
(name##_values)[i] = LLVMConstNull(elem); \
} \
} \
LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \
LLVMSetInitializer(name.addr.value, llvm_const_array(m, elem, name##_values, at->Array.count)); \
})
type_info_allocate_values(lb_global_type_info_member_types);
@@ -394,8 +394,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
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;
Entity *e = decl->entity.load();
if (e && e->kind == Entity_Procedure) {
proc_name = e->token.string;
}
}
TokenPos pos = t->Named.type_name->token.pos;
@@ -751,8 +752,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
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);
LLVMValueRef name_init = llvm_const_array(m, lb_type(m, t_string), name_values, cast(unsigned)fields.count);
LLVMValueRef value_init = llvm_const_array(m, 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);
LLVMSetGlobalConstant(name_array.value, true);
+289
View File
@@ -2787,3 +2787,292 @@ gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
ExactValue value = type_and_value_of_expr(expr).value;
return llvm_atomic_ordering_from_odin(value);
}
struct lbDiagParaPolyEntry {
Entity *entity;
String canonical_name;
isize count;
isize total_code_size;
};
gb_internal isize lb_total_code_size(lbProcedure *p) {
isize instruction_count = 0;
LLVMBasicBlockRef first = LLVMGetFirstBasicBlock(p->value);
for (LLVMBasicBlockRef block = first; block != nullptr; block = LLVMGetNextBasicBlock(block)) {
for (LLVMValueRef instr = LLVMGetFirstInstruction(block); instr != nullptr; instr = LLVMGetNextInstruction(instr)) {
instruction_count += 1;
}
}
return instruction_count;
}
gb_internal void lb_do_para_poly_diagnostics(lbGenerator *gen) {
PtrMap<Entity * /* Parent */, lbDiagParaPolyEntry> procs = {};
map_init(&procs);
defer (map_destroy(&procs));
for (auto &entry : gen->modules) {
lbModule *m = entry.value;
for (lbProcedure *p : m->generated_procedures) {
Entity *e = p->entity;
if (e == nullptr) {
continue;
}
if (p->builder == nullptr) {
continue;
}
DeclInfo *d = e->decl_info;
Entity *para_poly_parent = d->para_poly_original;
if (para_poly_parent == nullptr) {
continue;
}
lbDiagParaPolyEntry *entry = map_get(&procs, para_poly_parent);
if (entry == nullptr) {
lbDiagParaPolyEntry entry = {};
entry.entity = para_poly_parent;
entry.count = 0;
gbString w = string_canonical_entity_name(permanent_allocator(), entry.entity);
String name = make_string_c(w);
for (isize i = 0; i < name.len; i++) {
String s = substring(name, i, name.len);
if (string_starts_with(s, str_lit(":proc"))) {
name = substring(name, 0, i);
break;
}
}
entry.canonical_name = name;
map_set(&procs, para_poly_parent, entry);
}
entry = map_get(&procs, para_poly_parent);
GB_ASSERT(entry != nullptr);
entry->count += 1;
entry->total_code_size += lb_total_code_size(p);
}
}
auto entries = array_make<lbDiagParaPolyEntry>(heap_allocator(), 0, procs.count);
defer (array_free(&entries));
for (auto &entry : procs) {
array_add(&entries, entry.value);
}
array_sort(entries, [](void const *a, void const *b) -> int {
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
if (x->total_code_size > y->total_code_size) {
return -1;
}
if (x->total_code_size < y->total_code_size) {
return +1;
}
return string_compare(x->canonical_name, y->canonical_name);
});
gb_printf("Parametric Polymorphic Procedure Diagnostics\n");
gb_printf("------------------------------------------------------------------------------------------\n");
gb_printf("Sorted by Total Instruction Count Descending (Top 100)\n\n");
gb_printf("Total Instruction Count | Instantiation Count | Average Instruction Count | Procedure Name\n");
isize max_count = 100;
for (auto &entry : entries) {
isize code_size = entry.total_code_size;
isize count = entry.count;
String name = entry.canonical_name;
f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
gb_printf("%23td | %19td | %25.2f | %.*s\n", code_size, count, average, LIT(name));
if (max_count-- <= 0) {
break;
}
}
gb_printf("------------------------------------------------------------------------------------------\n");
array_sort(entries, [](void const *a, void const *b) -> int {
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
if (x->count > y->count) {
return -1;
}
if (x->count < y->count) {
return +1;
}
return string_compare(x->canonical_name, y->canonical_name);
});
gb_printf("Sorted by Total Instantiation Count Descending (Top 100)\n\n");
gb_printf("Instantiation Count | Total Instruction Count | Average Instruction Count | Procedure Name\n");
max_count = 100;
for (auto &entry : entries) {
isize code_size = entry.total_code_size;
isize count = entry.count;
String name = entry.canonical_name;
f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
gb_printf("%19td | %23td | %25.2f | %.*s\n", count, code_size, average, LIT(name));
if (max_count-- <= 0) {
break;
}
}
gb_printf("------------------------------------------------------------------------------------------\n");
array_sort(entries, [](void const *a, void const *b) -> int {
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
if (x->count < y->count) {
return -1;
}
if (x->count > y->count) {
return +1;
}
if (x->total_code_size > y->total_code_size) {
return -1;
}
if (x->total_code_size < y->total_code_size) {
return +1;
}
return string_compare(x->canonical_name, y->canonical_name);
});
gb_printf("Single Instanced Parametric Polymorphic Procedures\n\n");
gb_printf("Instruction Count | Procedure Name\n");
for (auto &entry : entries) {
isize code_size = entry.total_code_size;
isize count = entry.count;
String name = entry.canonical_name;
if (count != 1) {
break;
}
gb_printf("%17td | %.*s\n", code_size, LIT(name));
}
}
struct lbDiagModuleEntry {
lbModule *m;
String name;
isize global_internal_count;
isize global_external_count;
isize proc_internal_count;
isize proc_external_count;
isize total_instruction_count;
};
gb_internal void lb_do_module_diagnostics(lbGenerator *gen) {
Array<lbDiagModuleEntry> modules = {};
array_init(&modules, heap_allocator());
defer (array_free(&modules));
for (auto &em : gen->modules) {
lbModule *m = em.value;
{
lbDiagModuleEntry entry = {};
entry.m = m;
entry.name = make_string_c(m->module_name);
array_add(&modules, entry);
}
lbDiagModuleEntry &entry = modules[modules.count-1];
for (LLVMValueRef p = LLVMGetFirstFunction(m->mod); p != nullptr; p = LLVMGetNextFunction(p)) {
LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(p);
if (block == nullptr) {
entry.proc_external_count += 1;
} else {
entry.proc_internal_count += 1;
for (; block != nullptr; block = LLVMGetNextBasicBlock(block)) {
for (LLVMValueRef i = LLVMGetFirstInstruction(block); i != nullptr; i = LLVMGetNextInstruction(i)) {
entry.total_instruction_count += 1;
}
}
}
}
for (LLVMValueRef g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) {
LLVMLinkage linkage = LLVMGetLinkage(g);
if (linkage == LLVMExternalLinkage) {
entry.global_external_count += 1;
} else {
entry.global_internal_count += 1;
}
}
}
array_sort(modules, [](void const *a, void const *b) -> int {
lbDiagModuleEntry *x = cast(lbDiagModuleEntry *)a;
lbDiagModuleEntry *y = cast(lbDiagModuleEntry *)b;
if (x->total_instruction_count > y->total_instruction_count) {
return -1;
}
if (x->total_instruction_count < y->total_instruction_count) {
return +1;
}
return string_compare(x->name, y->name);
});
gb_printf("Module Diagnostics\n\n");
gb_printf("Total Instructions | Global Internals | Global Externals | Proc Internals | Proc Externals | Files | Instructions/File | Instructions/Proc | Module Name\n");
gb_printf("-------------------+------------------+------------------+----------------+----------------+-------+-------------------+-------------------+------------\n");
for (auto &entry : modules) {
isize file_count = 1;
if (entry.m->file != nullptr) {
file_count = 1;
} else if (entry.m->pkg) {
file_count = entry.m->pkg->files.count;
}
f64 instructions_per_file = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)file_count);
f64 instructions_per_proc = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)entry.proc_internal_count);
gb_printf("%18td | %16td | %16td | %14td | %14td | %5td | %17.1f | %17.1f | %s \n",
entry.total_instruction_count,
entry.global_internal_count,
entry.global_external_count,
entry.proc_internal_count,
entry.proc_external_count,
file_count,
instructions_per_file,
instructions_per_proc,
entry.m->module_name);
}
}
gb_internal void lb_do_build_diagnostics(lbGenerator *gen) {
lb_do_para_poly_diagnostics(gen);
gb_printf("------------------------------------------------------------------------------------------\n");
gb_printf("------------------------------------------------------------------------------------------\n\n");
lb_do_module_diagnostics(gen);
gb_printf("------------------------------------------------------------------------------------------\n");
gb_printf("------------------------------------------------------------------------------------------\n\n");
}
+26 -2
View File
@@ -394,6 +394,8 @@ enum BuildFlagKind {
BuildFlag_IntegerDivisionByZero,
BuildFlag_BuildDiagnostics,
// internal use only
BuildFlag_InternalFastISel,
BuildFlag_InternalIgnoreLazy,
@@ -403,6 +405,8 @@ enum BuildFlagKind {
BuildFlag_InternalCached,
BuildFlag_InternalNoInline,
BuildFlag_InternalByValue,
BuildFlag_InternalWeakMonomorphization,
BuildFlag_InternalLLVMVerification,
BuildFlag_Tilde,
@@ -617,6 +621,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
@@ -626,6 +631,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalWeakMonomorphization, str_lit("internal-weak-monomorphization"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalLLVMVerification, str_lit("internal-ignore-llvm-verification"), BuildFlagParam_None, Command_all);
#if ALLOW_TILDE
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
@@ -1558,6 +1565,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
break;
case BuildFlag_BuildDiagnostics:
build_context.build_diagnostics = true;
break;
case BuildFlag_InternalFastISel:
build_context.fast_isel = true;
break;
@@ -1584,6 +1595,13 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_InternalByValue:
build_context.internal_by_value = true;
break;
case BuildFlag_InternalWeakMonomorphization:
build_context.internal_weak_monomorphization = true;
break;
case BuildFlag_InternalLLVMVerification:
build_context.internal_ignore_llvm_verification = true;
break;
case BuildFlag_Tilde:
build_context.tilde_backend = true;
@@ -2826,7 +2844,7 @@ gb_internal int print_show_help(String const arg0, String command, String option
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
print_usage_line(2, "Errs when the attached-brace style is not adhered to (also known as 1TBS).");
print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
}
}
@@ -3050,7 +3068,8 @@ gb_internal void print_show_unused(Checker *c) {
if (e->token.string == "_") {
continue;
}
if (ptr_set_exists(&info->minimum_dependency_set, e)) {
if (e->min_dep_count.load(std::memory_order_relaxed) > 0) {
continue;
}
array_add(&unused, e);
@@ -3617,6 +3636,11 @@ int main(int arg_count, char const **arg_ptr) {
// print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0]));
// return 1;
// }
// Warn about Windows i386 thread-local storage limitations
if (build_context.metrics.arch == TargetArch_i386 && build_context.metrics.os == TargetOs_windows) {
gb_printf_err("Warning: Thread-local storage is disabled on Windows i386.\n");
}
// Check chosen microarchitecture. If not found or ?, print list.
bool print_microarch_list = true;
+57 -4
View File
@@ -57,10 +57,13 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
usize mask = s->capacity-1;
usize hash_index = cast(usize)hash & mask;
for (usize i = 0; i < s->capacity; i++) {
Type *key = s->keys[hash_index].type;
if (are_types_identical_unique_tuples(key, pair.type)) {
auto *e = &s->keys[hash_index];
u64 hash = e->hash;
Type *key = e->type;
if (hash == pair.hash &&
are_types_identical_unique_tuples(key, pair.type)) {
return hash_index;
} else if (key == 0) {
} else if (key == nullptr) {
return -1;
}
hash_index = (hash_index+1)&mask;
@@ -164,6 +167,48 @@ gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it
return type_set_update(s, pair);
}
gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m) { // returns true if it previously existsed
rwlock_acquire_upgrade(m);
if (type_set_exists(s, pair)) {
rwlock_release_upgrade(m);
return true;
}
rwlock_release_upgrade_and_acquire_write(m);
defer (rwlock_release_write(m));
if (s->keys == nullptr) {
type_set_init(s);
} else if (type_set__full(s)) {
type_set_grow(s);
}
GB_ASSERT(s->count < s->capacity);
GB_ASSERT(s->capacity >= 0);
usize mask = s->capacity-1;
usize hash = cast(usize)pair.hash;
usize hash_index = (cast(usize)hash) & mask;
GB_ASSERT(hash_index < s->capacity);
for (usize i = 0; i < s->capacity; i++) {
TypeInfoPair *key = &s->keys[hash_index];
GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
*key = pair;
s->count++;
return false;
}
hash_index = (hash_index+1)&mask;
}
GB_PANIC("ptr set out of memory");
return false;
}
gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m) { // returns true if it previously existsed
TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
return type_set_update_with_mutex(s, pair, m);
}
gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
type_set_update(s, ptr);
@@ -328,12 +373,20 @@ gb_internal u64 type_hash_canonical_type(Type *type) {
if (type == nullptr) {
return 0;
}
u64 prev_hash = type->canonical_hash.load(std::memory_order_relaxed);
if (prev_hash != 0) {
return prev_hash;
}
u64 hash = fnv64a(nullptr, 0);
TypeWriter w = {};
type_writer_make_hasher(&w, &hash);
write_type_to_canonical_string(&w, type);
hash = hash ? hash : 1;
return hash ? hash : 1;
type->canonical_hash.store(hash, std::memory_order_relaxed);
return hash;
}
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
+2
View File
@@ -102,6 +102,8 @@ gb_internal Type *type_set_add (TypeSet *s, Type *ptr);
gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair);
gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed
gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed
gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m);
gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m);
gb_internal bool type_set_exists (TypeSet *s, Type *ptr);
gb_internal void type_set_remove (TypeSet *s, Type *ptr);
gb_internal void type_set_clear (TypeSet *s);
+14 -1
View File
@@ -1,5 +1,7 @@
#include "parser_pos.cpp"
gb_global std::atomic<bool> g_parsing_done;
gb_internal bool in_vet_packages(AstFile *file) {
if (file == nullptr) {
return true;
@@ -176,7 +178,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
return nullptr;
}
if (f == nullptr) {
f = node->thread_safe_file();
if (g_parsing_done.load(std::memory_order_relaxed)) {
f = node->file();
} else {
f = node->thread_safe_file();
}
}
Ast *n = alloc_ast_node(f, node->kind);
gb_memmove(n, node, ast_node_size(node->kind));
@@ -744,6 +750,7 @@ gb_internal Ast *ast_matrix_index_expr(AstFile *f, Ast *expr, Token open, Token
gb_internal Ast *ast_ident(AstFile *f, Token token) {
Ast *result = alloc_ast_node(f, Ast_Ident);
result->Ident.token = token;
result->Ident.hash = string_hash(token.string);
return result;
}
@@ -6592,6 +6599,10 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
} else if (string_starts_with(lc, str_lit("vet"))) {
f->vet_flags = parse_vet_tag(tok, lc);
f->vet_flags_set = true;
} else if (string_starts_with(lc, str_lit("test"))) {
if ((build_context.command_kind & Command_test) == 0) {
return false;
}
} else if (string_starts_with(lc, str_lit("ignore"))) {
return false;
} else if (string_starts_with(lc, str_lit("private"))) {
@@ -6962,6 +6973,8 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
}
}
g_parsing_done.store(true, std::memory_order_relaxed);
return ParseFile_None;
}
+19
View File
@@ -27,6 +27,24 @@ enum AddressingMode : u8 {
Addressing_SwizzleVariable = 14, // Swizzle indexed variable
};
gb_global String const addressing_mode_strings[] = {
str_lit("Invalid"),
str_lit("NoValue"),
str_lit("Value"),
str_lit("Context"),
str_lit("Variable"),
str_lit("Constant"),
str_lit("Type"),
str_lit("Builtin"),
str_lit("ProcGroup"),
str_lit("MapIndex"),
str_lit("OptionalOk"),
str_lit("OptionalOkPtr"),
str_lit("SoaVariable"),
str_lit("SwizzleValue"),
str_lit("SwizzleVariable"),
};
struct TypeAndValue {
Type * type;
AddressingMode mode;
@@ -396,6 +414,7 @@ struct AstSplitArgs {
AST_KIND(Ident, "identifier", struct { \
Token token; \
Entity *entity; \
u32 hash; \
}) \
AST_KIND(Implicit, "implicit", Token) \
AST_KIND(Uninit, "uninitialized value", Token) \
+45 -3
View File
@@ -16,6 +16,8 @@ template <typename T> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr);
template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr);
template <typename T> gb_internal void ptr_set_clear (PtrSet<T> *s);
#define FOR_PTR_SET(element, set_) for (auto *it = &(set_).keys[0], element = it ? *it : nullptr; (set_).keys != nullptr && it < &(set_).keys[(set_).capacity]; it++) if (element = *it, (*it != nullptr && *it != cast(void *)~(uintptr)(0ull)))
gb_internal gbAllocator ptr_set_allocator(void) {
return heap_allocator();
}
@@ -83,7 +85,7 @@ gb_internal gb_inline void ptr_set_grow(PtrSet<T> *old_set) {
PtrSet<T> new_set = {};
ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
for (T ptr : *old_set) {
FOR_PTR_SET(ptr, *old_set) {
bool was_new = ptr_set_update(&new_set, ptr);
GB_ASSERT(!was_new);
}
@@ -134,6 +136,44 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre
return false;
}
template <typename T>
gb_internal bool ptr_set_update_with_mutex(PtrSet<T> *s, T ptr, RWSpinLock *m) { // returns true if it previously existsed
rwlock_acquire_upgrade(m);
if (ptr_set_exists(s, ptr)) {
rwlock_release_upgrade(m);
return true;
}
rwlock_release_upgrade_and_acquire_write(m);
defer (rwlock_release_write(m));
if (s->keys == nullptr) {
ptr_set_init(s);
} else if (ptr_set__full(s)) {
ptr_set_grow(s);
}
GB_ASSERT(s->count < s->capacity);
GB_ASSERT(s->capacity >= 0);
usize mask = s->capacity-1;
u32 hash = ptr_map_hash_key(ptr);
usize hash_index = (cast(usize)hash) & mask;
GB_ASSERT(hash_index < s->capacity);
for (usize i = 0; i < s->capacity; i++) {
T *key = &s->keys[hash_index];
GB_ASSERT(*key != ptr);
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) {
*key = ptr;
s->count++;
return false;
}
hash_index = (hash_index+1)&mask;
}
GB_PANIC("ptr set out of memory");
return false;
}
template <typename T>
gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) {
ptr_set_update(s, ptr);
@@ -157,7 +197,7 @@ gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) {
gb_zero_size(s->keys, s->capacity*gb_size_of(T));
}
template <typename T>
/*template <typename T>
struct PtrSetIterator {
PtrSet<T> *set;
usize index;
@@ -201,4 +241,6 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
template <typename T>
gb_internal PtrSetIterator<T> end(PtrSet<T> &set) noexcept {
return PtrSetIterator<T>{&set, set.capacity};
}
}*/
+2 -1
View File
@@ -36,7 +36,8 @@ gb_internal void mpsc_destroy(MPSCQueue<T> *q) {
template <typename T>
gb_internal MPSCNode<T> *mpsc_alloc_node(MPSCQueue<T> *q, T const &value) {
auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
// auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
auto new_node = gb_alloc_item(permanent_allocator(), MPSCNode<T>);
new_node->value = value;
return new_node;
}
+15 -10
View File
@@ -633,23 +633,28 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr);
}
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
#include <iconv.h>
#include <wchar.h>
gb_internal int convert_multibyte_to_widechar(char const *multibyte_input, usize input_length, wchar_t *output, usize output_size) {
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
String string = copy_string(heap_allocator(), make_string(cast(u8 const*)multibyte_input, input_length)); /* Guarantee NULL terminator */
u8* input = string.text;
return cast(int)result;
mbstate_t ps = { 0 };
size_t result = mbsrtowcs(output, cast(const char**)&input, output_size, &ps);
gb_free(heap_allocator(), string.text);
return (result == (size_t)-1) ? -1 : (int)result;
}
gb_internal int convert_widechar_to_multibyte(wchar_t const *widechar_input, usize input_length, char* output, usize output_size) {
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
size_t result = iconv(conv, cast(char**) &widechar_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
String string = copy_string(heap_allocator(), make_string(cast(u8 const*)widechar_input, input_length)); /* Guarantee NULL terminator */
u8* input = string.text;
return cast(int)result;
mbstate_t ps = { 0 };
size_t result = wcsrtombs(output, cast(const wchar_t**)&input, output_size, &ps);
gb_free(heap_allocator(), string.text);
return (result == (size_t)-1) ? -1 : (int)result;
}
#else
#error Implement system
+14 -6
View File
@@ -19,6 +19,11 @@ enum GrabState {
Grab_Failed = 2,
};
enum BroadcastWaitState {
Nobody_Waiting = 0,
Someone_Waiting = 1,
};
struct ThreadPool {
gbAllocator threads_allocator;
Slice<Thread> threads;
@@ -54,8 +59,8 @@ gb_internal void thread_pool_destroy(ThreadPool *pool) {
for_array_off(i, 1, pool->threads) {
Thread *t = &pool->threads[i];
pool->tasks_available.fetch_add(1, std::memory_order_acquire);
futex_broadcast(&pool->tasks_available);
pool->tasks_available.store(Nobody_Waiting);
futex_broadcast(&t->pool->tasks_available);
thread_join_and_destroy(t);
}
@@ -87,8 +92,10 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) {
thread->queue.bottom.store(bot + 1, std::memory_order_relaxed);
thread->pool->tasks_left.fetch_add(1, std::memory_order_release);
thread->pool->tasks_available.fetch_add(1, std::memory_order_relaxed);
futex_broadcast(&thread->pool->tasks_available);
i32 state = Someone_Waiting;
if (thread->pool->tasks_available.compare_exchange_strong(state, Nobody_Waiting)) {
futex_broadcast(&thread->pool->tasks_available);
}
}
GrabState thread_pool_queue_take(Thread *thread, WorkerTask *task) {
@@ -230,12 +237,13 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) {
}
// if we've done all our work, and there's nothing to steal, go to sleep
state = pool->tasks_available.load(std::memory_order_acquire);
pool->tasks_available.store(Someone_Waiting);
if (!pool->running) { break; }
futex_wait(&pool->tasks_available, state);
futex_wait(&pool->tasks_available, Someone_Waiting);
main_loop_continue:;
}
return 0;
}
+48 -2
View File
@@ -195,7 +195,13 @@ gb_internal void mutex_lock(RecursiveMutex *m) {
// inside the lock
return;
}
futex_wait(&m->owner, prev_owner);
// NOTE(lucas): we are doing spin lock since futex signal is expensive on OSX. The recursive locks are
// very short lived so we don't hit this mega often and I see no perform regression on windows (with
// a performance uplift on OSX).
//futex_wait(&m->owner, prev_owner);
yield_thread();
}
}
gb_internal bool mutex_try_lock(RecursiveMutex *m) {
@@ -216,7 +222,9 @@ gb_internal void mutex_unlock(RecursiveMutex *m) {
return;
}
m->owner.exchange(0, std::memory_order_release);
futex_signal(&m->owner);
// NOTE(lucas): see comment about spin lock in mutex_lock above
// futex_signal(&m->owner);
// outside the lock
}
@@ -448,6 +456,44 @@ gb_internal void semaphore_wait(Semaphore *s) {
}
#endif
static const int RWLOCK_WRITER = 1<<0;
static const int RWLOCK_UPGRADED = 1<<1;
static const int RWLOCK_READER = 1<<2;
struct RWSpinLock {
Futex bits;
};
void rwlock_release_write(RWSpinLock *l) {
l->bits.fetch_and(~(RWLOCK_WRITER | RWLOCK_UPGRADED), std::memory_order_release);
futex_signal(&l->bits);
}
bool rwlock_try_acquire_upgrade(RWSpinLock *l) {
int value = l->bits.fetch_or(RWLOCK_UPGRADED, std::memory_order_acquire);
return (value & (RWLOCK_UPGRADED | RWLOCK_WRITER)) == 0;
}
void rwlock_acquire_upgrade(RWSpinLock *l) {
while (!rwlock_try_acquire_upgrade(l)) {
futex_wait(&l->bits, RWLOCK_UPGRADED | RWLOCK_WRITER);
}
}
void rwlock_release_upgrade(RWSpinLock *l) {
l->bits.fetch_add(-RWLOCK_UPGRADED, std::memory_order_acq_rel);
}
bool rwlock_try_release_upgrade_and_acquire_write(RWSpinLock *l) {
int expect = RWLOCK_UPGRADED;
return l->bits.compare_exchange_strong(expect, RWLOCK_WRITER, std::memory_order_acq_rel);
}
void rwlock_release_upgrade_and_acquire_write(RWSpinLock *l) {
while (!rwlock_try_release_upgrade_and_acquire_write(l)) {
futex_wait(&l->bits, RWLOCK_UPGRADED);
}
}
struct Parker {
Futex state;
};
+106 -23
View File
@@ -206,13 +206,18 @@ struct TypeProc {
bool optional_ok;
};
struct TypeNamed {
String name;
Type * base;
Entity *type_name; /* Entity_TypeName */
BlockingMutex gen_types_data_mutex;
GenTypesData *gen_types_data;
};
#define TYPE_KINDS \
TYPE_KIND(Basic, BasicType) \
TYPE_KIND(Named, struct { \
String name; \
Type * base; \
Entity *type_name; /* Entity_TypeName */ \
}) \
TYPE_KIND(Named, TypeNamed) \
TYPE_KIND(Generic, struct { \
i64 id; \
String name; \
@@ -334,6 +339,7 @@ struct Type {
// NOTE(bill): These need to be at the end to not affect the unionized data
std::atomic<i64> cached_size;
std::atomic<i64> cached_align;
std::atomic<u64> canonical_hash;
std::atomic<u32> flags; // TypeFlag
bool failure;
};
@@ -429,11 +435,8 @@ gb_internal Selection make_selection(Entity *entity, Array<i32> index, bool indi
}
gb_internal void selection_add_index(Selection *s, isize index) {
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
// of heap allocation
// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
if (s->index.data == nullptr) {
array_init(&s->index, heap_allocator());
array_init(&s->index, permanent_allocator());
}
array_add(&s->index, cast(i32)index);
}
@@ -441,7 +444,7 @@ gb_internal void selection_add_index(Selection *s, isize index) {
gb_internal Selection selection_combine(Selection const &lhs, Selection const &rhs) {
Selection new_sel = lhs;
new_sel.indirect = lhs.indirect || rhs.indirect;
new_sel.index = array_make<i32>(heap_allocator(), lhs.index.count+rhs.index.count);
new_sel.index = array_make<i32>(permanent_allocator(), lhs.index.count+rhs.index.count);
array_copy(&new_sel.index, lhs.index, 0);
array_copy(&new_sel.index, rhs.index, lhs.index.count);
return new_sel;
@@ -1230,7 +1233,6 @@ gb_internal bool is_type_named(Type *t) {
}
gb_internal bool is_type_boolean(Type *t) {
// t = core_type(t);
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
@@ -1239,7 +1241,6 @@ gb_internal bool is_type_boolean(Type *t) {
return false;
}
gb_internal bool is_type_integer(Type *t) {
// t = core_type(t);
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
@@ -1249,6 +1250,7 @@ gb_internal bool is_type_integer(Type *t) {
}
gb_internal bool is_type_integer_like(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Boolean)) != 0;
}
@@ -1281,7 +1283,6 @@ gb_internal bool is_type_integer_128bit(Type *t) {
return false;
}
gb_internal bool is_type_rune(Type *t) {
// t = core_type(t);
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
@@ -1290,7 +1291,6 @@ gb_internal bool is_type_rune(Type *t) {
return false;
}
gb_internal bool is_type_numeric(Type *t) {
// t = core_type(t);
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
@@ -1377,14 +1377,20 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
gb_internal bool is_type_constant_type(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
switch (t->kind) {
case Type_Basic:
if (t->Basic.kind == Basic_typeid) {
return true;
}
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
}
if (t->kind == Type_BitSet) {
case Type_BitSet:
return true;
}
if (t->kind == Type_Proc) {
case Type_Proc:
return true;
case Type_Array:
return is_type_constant_type(t->Array.elem);
case Type_EnumeratedArray:
return is_type_constant_type(t->EnumeratedArray.elem);
}
return false;
}
@@ -1448,24 +1454,28 @@ gb_internal bool is_type_tuple(Type *t) {
return t->kind == Type_Tuple;
}
gb_internal bool is_type_uintptr(Type *t) {
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.kind == Basic_uintptr);
}
return false;
}
gb_internal bool is_type_rawptr(Type *t) {
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_rawptr;
}
return false;
}
gb_internal bool is_type_u8(Type *t) {
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_u8;
}
return false;
}
gb_internal bool is_type_u16(Type *t) {
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_u16;
}
@@ -1612,6 +1622,7 @@ gb_internal bool is_matrix_square(Type *t) {
gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
if (is_type_integer(t)) {
return true;
} else if (is_type_float(t)) {
@@ -1839,40 +1850,49 @@ gb_internal Type *base_complex_elem_type(Type *t) {
gb_internal bool is_type_struct(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_Struct;
}
gb_internal bool is_type_union(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_Union;
}
gb_internal bool is_type_soa_struct(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None;
}
gb_internal bool is_type_raw_union(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_Struct && t->Struct.is_raw_union);
}
gb_internal bool is_type_enum(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_Enum);
}
gb_internal bool is_type_bit_set(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_BitSet);
}
gb_internal bool is_type_bit_field(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_BitField);
}
gb_internal bool is_type_map(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_Map;
}
gb_internal bool is_type_union_maybe_pointer(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Union && t->Union.variants.count == 1) {
Type *v = t->Union.variants[0];
return is_type_internally_pointer_like(v);
@@ -1883,6 +1903,7 @@ gb_internal bool is_type_union_maybe_pointer(Type *t) {
gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Union && t->Union.variants.count == 1) {
Type *v = t->Union.variants[0];
if (is_type_internally_pointer_like(v)) {
@@ -1917,6 +1938,7 @@ gb_internal TypeEndianKind type_endian_kind_of(Type *t) {
gb_internal bool is_type_endian_big(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
if (t->Basic.flags & BasicFlag_EndianBig) {
return true;
@@ -1933,6 +1955,7 @@ gb_internal bool is_type_endian_big(Type *t) {
}
gb_internal bool is_type_endian_little(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
if (t->Basic.flags & BasicFlag_EndianLittle) {
return true;
@@ -1950,6 +1973,7 @@ gb_internal bool is_type_endian_little(Type *t) {
gb_internal bool is_type_endian_platform(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & (BasicFlag_EndianLittle|BasicFlag_EndianBig)) == 0;
} else if (t->kind == Type_BitSet) {
@@ -1965,6 +1989,7 @@ gb_internal bool types_have_same_internal_endian(Type *a, Type *b) {
}
gb_internal bool is_type_endian_specific(Type *t) {
t = core_type(t);
if (t == nullptr) { return false; }
if (t->kind == Type_BitSet) {
t = bit_set_to_int(t);
}
@@ -2062,19 +2087,23 @@ gb_internal Type *integer_endian_type_to_platform_type(Type *t) {
gb_internal bool is_type_any(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_Basic && t->Basic.kind == Basic_any);
}
gb_internal bool is_type_typeid(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return (t->kind == Type_Basic && t->Basic.kind == Basic_typeid);
}
gb_internal bool is_type_untyped_nil(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit));
}
gb_internal bool is_type_untyped_uninit(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit);
}
@@ -2484,18 +2513,70 @@ gb_internal bool type_has_nil(Type *t) {
return false;
}
gb_internal bool is_type_union_constantable(Type *type) {
Type *bt = base_type(type);
GB_ASSERT(bt->kind == Type_Union);
if (bt->Union.variants.count == 0) {
return true;
} else if (bt->Union.variants.count == 1) {
return is_type_constant_type(bt->Union.variants[0]);
}
for (Type *v : bt->Union.variants) {
if (!is_type_constant_type(v)) {
return false;
}
}
return true;
}
gb_internal bool is_type_raw_union_constantable(Type *type) {
Type *bt = base_type(type);
GB_ASSERT(bt->kind == Type_Struct);
GB_ASSERT(bt->Struct.is_raw_union);
for (Entity *f : bt->Struct.fields) {
if (!is_type_constant_type(f->type)) {
return false;
}
}
// return true;
return false; // Disable raw union constants for the time being
}
gb_internal bool elem_type_can_be_constant(Type *t) {
t = base_type(t);
if (t == t_invalid) {
return false;
}
if (is_type_any(t) || is_type_union(t) || is_type_raw_union(t)) {
if (is_type_any(t)) {
return false;
}
if (is_type_raw_union(t)) {
return is_type_raw_union_constantable(t);
}
if (is_type_union(t)) {
return is_type_union_constantable(t);
}
return true;
}
gb_internal bool elem_cannot_be_constant(Type *t) {
if (is_type_any(t)) {
return true;
}
if (is_type_union(t)) {
return !is_type_union_constantable(t);
}
if (is_type_raw_union(t)) {
return !is_type_raw_union_constantable(t);
}
return false;
}
gb_internal bool is_type_lock_free(Type *t) {
t = core_type(t);
if (t == t_invalid) {
@@ -2837,6 +2918,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) {
return false;
}
// MUTEX_GUARD(&g_type_mutex);
return are_types_identical_internal(x, y, false);
}
gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) {
@@ -2864,6 +2946,7 @@ gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) {
return false;
}
// MUTEX_GUARD(&g_type_mutex);
return are_types_identical_internal(x, y, true);
}
@@ -3932,7 +4015,7 @@ gb_internal i64 type_size_of(Type *t) {
TypePath path{};
type_path_init(&path);
{
MUTEX_GUARD(&g_type_mutex);
// MUTEX_GUARD(&g_type_mutex);
size = type_size_of_internal(t, &path);
t->cached_size.store(size);
}
@@ -3952,7 +4035,7 @@ gb_internal i64 type_align_of(Type *t) {
TypePath path{};
type_path_init(&path);
{
MUTEX_GUARD(&g_type_mutex);
// MUTEX_GUARD(&g_type_mutex);
t->cached_align.store(type_align_of_internal(t, &path));
}
type_path_free(&path);
@@ -4678,7 +4761,7 @@ gb_internal Type *alloc_type_tuple_from_field_types(Type **field_types, isize fi
}
Type *t = alloc_type_tuple();
t->Tuple.variables = slice_make<Entity *>(heap_allocator(), field_count);
t->Tuple.variables = slice_make<Entity *>(permanent_allocator(), field_count);
Scope *scope = nullptr;
for_array(i, t->Tuple.variables) {